/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "GacUICompiler.h"

/***********************************************************************
.\GUICPPGEN.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace stream;
		using namespace filesystem;
		using namespace workflow;
		using namespace workflow::cppcodegen;

		bool WriteErrors(
			collections::List<GuiResourceError>& errors,
			const filesystem::FilePath& errorPath)
		{
			List<WString> output;
			GuiResourceError::SortAndLog(errors, output);
			return File(errorPath).WriteAllLines(output, true, BomEncoder::Utf8);
		}

		Ptr<GuiResourceFolder> PrecompileResource(
			Ptr<GuiResource> resource,
			GuiResourceCpuArchitecture targetCpuArchitecture,
			IGuiResourcePrecompileCallback* callback,
			collections::List<GuiResourceError>& errors)
		{
			auto precompiledFolder = resource->Precompile(targetCpuArchitecture, callback, errors);
			return precompiledFolder;
		}

		Ptr<GuiInstanceCompiledWorkflow> WriteWorkflowScript(
			Ptr<GuiResourceFolder> precompiledFolder,
			const WString& assemblyResourcePath,
			const filesystem::FilePath& workflowPath)
		{
			if (precompiledFolder)
			{
				if (auto compiled = precompiledFolder->GetValueByPath(assemblyResourcePath).Cast<GuiInstanceCompiledWorkflow>())
				{
					WString text;
					if (compiled->assembly)
					{
						auto& codes = compiled->assembly->insAfterCodegen->moduleCodes;
						for (auto [code, codeIndex] : indexed(codes))
						{
							text += L"================================(" + itow(codeIndex + 1) + L"/" + itow(codes.Count()) + L")================================\r\n";
							text += code + L"\r\n";
						}
					}
					else
					{
						for (auto [moduleRecord, codeIndex] : indexed(compiled->modules))
						{
							WString code = GenerateToStream([&, module = moduleRecord.module](StreamWriter& writer)
							{
								WfPrint(module, L"", writer);
							});
							text += L"================================(" + itow(codeIndex + 1) + L"/" + itow(compiled->modules.Count()) + L")================================\r\n";
							text += code + L"\r\n";
						}
					}

					if (File(workflowPath).WriteAllText(text, true, BomEncoder::Utf8))
					{
						return compiled;
					}
				}
			}
			return nullptr;
		}

		Ptr<workflow::cppcodegen::WfCppOutput> WriteCppCodesToFile(
			Ptr<GuiResource> resource,
			Ptr<GuiInstanceCompiledWorkflow> compiled,
			Ptr<workflow::cppcodegen::WfCppInput> cppInput,
			const filesystem::FilePath& cppFolder,
			collections::List<GuiResourceError>& errors)
		{
			auto output = GenerateCppFiles(cppInput, compiled->metadata.Obj());

			if (compiled->metadata->errors.Count() > 0)
			{
				for (auto error : compiled->metadata->errors)
				{
					errors.Add(GuiResourceError({ {resource} }, error.message));
				}
				return nullptr;
			}

			// TODO: (enumerable) foreach on dictionary
			for (auto [fileName, index] : indexed(output->cppFiles.Keys()))
			{
				WString code = output->cppFiles.Values()[index];
				File file(cppFolder / fileName);

				if (file.Exists())
				{
					WString inputText;
					BomEncoder::Encoding inputEncoding;
					bool inputBom;
					file.ReadAllTextWithEncodingTesting(inputText, inputEncoding, inputBom);
					code = MergeCppFileContent(inputText, code);
				}

				if (file.Exists())
				{
					WString inputText;
					BomEncoder::Encoding inputEncoding;
					bool inputBom;
					file.ReadAllTextWithEncodingTesting(inputText, inputEncoding, inputBom);
					if (inputText == code)
					{
						continue;
					}
				}
				file.WriteAllText(code, true, BomEncoder::Utf8);
			}
			return output;
		}

		bool WriteBinaryResource(
			Ptr<GuiResource> resource,
			bool compress,
			bool includeAssemblyInResource,
			Nullable<filesystem::FilePath> resourceOutput,
			Nullable<filesystem::FilePath> assemblyOutput)
		{
			auto precompiled = resource->GetFolder(L"Precompiled");
			auto folder = precompiled->GetFolder(L"Workflow");

			if (resourceOutput)
			{
				FileStream fileStream(resourceOutput.Value().GetFullPath(), FileStream::WriteOnly);
				if (!fileStream.IsAvailable()) return false;

				if (!includeAssemblyInResource) precompiled->RemoveFolder(L"Workflow");
				if (compress)
				{
					LzwEncoder encoder;
					EncoderStream encoderStream(fileStream, encoder);
					resource->SavePrecompiledBinary(encoderStream);
				}
				else
				{
					resource->SavePrecompiledBinary(fileStream);
				}
				if (!includeAssemblyInResource) precompiled->AddFolder(L"Workflow", folder);
			}

			if (assemblyOutput)
			{
				if (auto item = folder->GetItem(L"InstanceClass"))
				{
					if (auto compiled = item->GetContent().Cast<GuiInstanceCompiledWorkflow>())
					{
						if (compiled->assembly)
						{
							FileStream fileStream(assemblyOutput.Value().GetFullPath(), FileStream::WriteOnly);
							if (!fileStream.IsAvailable()) return false;
							compiled->assembly->Serialize(fileStream);
						}
					}
				}
			}

			return true;
		}

		void WriteEmbeddedBinaryClass(MemoryStream& binaryStream, bool compress, const WString& className, const WString& prefix, StreamWriter& writer)
		{
			MemoryStream compressedStream;
			binaryStream.SeekFromBegin(0);
			if (compress)
			{
				CompressStream(binaryStream, compressedStream);
			}
			else
			{
				CopyStream(binaryStream, compressedStream);
			}
			compressedStream.SeekFromBegin(0);

			vint lengthBeforeCompressing = (vint)binaryStream.Size();
			vint length = (vint)compressedStream.Size();
			const vint block = 1024;
			vint remain = length % block;
			vint solidRows = length / block;
			vint rows = solidRows + (remain ? 1 : 0);

#define PREFIX writer.WriteString(prefix);

			PREFIX writer.WriteLine(L"class " + className);
			PREFIX writer.WriteLine(L"{");
			PREFIX writer.WriteLine(L"public:");

			PREFIX writer.WriteLine(L"\tstatic const vint parserBufferLength = " + itow(length) + L"; // " + itow(lengthBeforeCompressing) + L" bytes before compressing");
			PREFIX writer.WriteLine(L"\tstatic const vint parserBufferBlock = " + itow(block) + L";");
			PREFIX writer.WriteLine(L"\tstatic const vint parserBufferRemain = " + itow(remain) + L";");
			PREFIX writer.WriteLine(L"\tstatic const vint parserBufferRows = " + itow(rows) + L";");
			PREFIX writer.WriteLine(L"\tstatic const char* parserBuffer[" + itow(rows) + L"];");
			writer.WriteLine(L"");

			PREFIX writer.WriteLine(L"\tstatic void ReadToStream(vl::stream::MemoryStream& stream)");
			PREFIX writer.WriteLine(L"\t{");
			PREFIX writer.WriteLine(L"\t\tDecompressStream(parserBuffer, " + WString(compress ? L"true" : L"false") + L", parserBufferRows, parserBufferBlock, parserBufferRemain, stream);");
			PREFIX writer.WriteLine(L"\t}");

			PREFIX writer.WriteLine(L"};");
			writer.WriteLine(L"");
			PREFIX writer.WriteLine(L"const char* " + className + L"::parserBuffer[] = {");

			char buffer[block];
			const wchar_t* hex = L"0123456789ABCDEF";
			for (vint i = 0; i < rows; i++)
			{
				vint size = i == solidRows ? remain : block;
				compressedStream.Read(buffer, size);
				PREFIX writer.WriteString(L"\t\"");
				for (vint j = 0; j < size; j++)
				{
					vuint8_t byte = buffer[j];
					writer.WriteString(L"\\x");
					writer.WriteChar(hex[byte / 16]);
					writer.WriteChar(hex[byte % 16]);
				}
				writer.WriteLine(L"\",");
			}
			PREFIX writer.WriteLine(L"\t};");

#undef PREFIX
		}

		bool WriteEmbeddedResource(Ptr<GuiResource> resource,
			Ptr<workflow::cppcodegen::WfCppInput> cppInput,
			Ptr<workflow::cppcodegen::WfCppOutput> cppOutput,
			bool compress,
			const filesystem::FilePath& filePath)
		{
			WString code = GenerateToStream([&](StreamWriter& writer)
			{
				writer.WriteLine(L"#include \"" + cppOutput->entryFileName + L".h\"");
				writer.WriteLine(L"");
				writer.WriteLine(L"namespace vl");
				writer.WriteLine(L"{");
				writer.WriteLine(L"\tnamespace presentation");
				writer.WriteLine(L"\t{");
				writer.WriteLine(L"\t\tnamespace user_resource");
				writer.WriteLine(L"\t\t{");
				writer.WriteLine(L"\t\t\tusing namespace collections;");
				writer.WriteLine(L"\t\t\tusing namespace stream;");
				writer.WriteLine(L"\t\t\tusing namespace controls;");
				writer.WriteLine(L"");

				{
					MemoryStream resourceStream;
					{
						auto precompiled = resource->GetFolder(L"Precompiled");
						auto folder = precompiled->GetFolder(L"Workflow");
						precompiled->RemoveFolder(L"Workflow");
						resource->SavePrecompiledBinary(resourceStream);
						precompiled->AddFolder(L"Workflow", folder);
					}
					WriteEmbeddedBinaryClass(resourceStream, compress, cppInput->assemblyName + L"ResourceReader", L"\t\t\t", writer);
					writer.WriteLine(L"");
				}
				{
					writer.WriteLine(L"\t\t\tclass " + cppInput->assemblyName + L"ResourceLoaderPlugin : public Object, public IGuiPlugin");
					writer.WriteLine(L"\t\t\t{");
					writer.WriteLine(L"\t\t\tpublic:");
					writer.WriteLine(L"");
					writer.WriteLine(L"\t\t\t\tGUI_PLUGIN_NAME(GacGen_" + cppInput->assemblyName + L"ResourceLoader)");
					writer.WriteLine(L"\t\t\t\t{");
					writer.WriteLine(L"\t\t\t\t\tGUI_PLUGIN_DEPEND(GacUI_Res_Resource);");
					writer.WriteLine(L"\t\t\t\t\tGUI_PLUGIN_DEPEND(GacUI_Res_TypeResolvers);");
					writer.WriteLine(L"#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA");
					writer.WriteLine(L"\t\t\t\t\tGUI_PLUGIN_DEPEND(GacUI_Instance_Reflection);");
					writer.WriteLine(L"\t\t\t\t\tGUI_PLUGIN_DEPEND(GacUI_Compiler_WorkflowTypeResolvers);");
					writer.WriteLine(L"#endif");
					writer.WriteLine(L"\t\t\t\t}");
					writer.WriteLine(L"");
					writer.WriteLine(L"\t\t\t\tvoid Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override");
					writer.WriteLine(L"\t\t\t\t{");
					writer.WriteLine(L"\t\t\t\t\tif (controllerRelatedPlugins)");
					writer.WriteLine(L"\t\t\t\t\t{");
					writer.WriteLine(L"\t\t\t\t\t\tList<GuiResourceError> errors;");
					writer.WriteLine(L"\t\t\t\t\t\tMemoryStream resourceStream;");
					writer.WriteLine(L"\t\t\t\t\t\t" + cppInput->assemblyName + L"ResourceReader::ReadToStream(resourceStream);");
					writer.WriteLine(L"\t\t\t\t\t\tresourceStream.SeekFromBegin(0);");
					writer.WriteLine(L"\t\t\t\t\t\tGetResourceManager()->LoadResourceOrPending(resourceStream, GuiResourceUsage::InstanceClass);");
					writer.WriteLine(L"\t\t\t\t\t}");
					writer.WriteLine(L"\t\t\t\t}");
					writer.WriteLine(L"");
					writer.WriteLine(L"\t\t\t\tvoid Unload(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override");
					writer.WriteLine(L"\t\t\t\t{");
					writer.WriteLine(L"\t\t\t\t}");
					writer.WriteLine(L"\t\t\t};");
					writer.WriteLine(L"\t\t\tGUI_REGISTER_PLUGIN(" + cppInput->assemblyName + L"ResourceLoaderPlugin)");
				}

				writer.WriteLine(L"\t\t}");
				writer.WriteLine(L"\t}");
				writer.WriteLine(L"}");
			});

			File file(filePath);
			if (file.Exists())
			{
				WString inputText;
				BomEncoder::Encoding inputEncoding;
				bool inputBom;
				file.ReadAllTextWithEncodingTesting(inputText, inputEncoding, inputBom);
				if (inputText == code)
				{
					return true;
				}
			}
			return file.WriteAllText(code, true, BomEncoder::Utf8);
		}
	}
}


/***********************************************************************
.\GUIINSTANCEANIMATION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace reflection::description;
		using namespace collections;
		using namespace glr::xml;
		using namespace workflow;
		using namespace workflow::analyzer;
		using namespace presentation::controls;

/***********************************************************************
GuiInstanceGradientAnimation::LoadFromXml
***********************************************************************/

		Ptr<GuiInstanceGradientAnimation> GuiInstanceGradientAnimation::LoadFromXml(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlDocument> xml, GuiResourceError::List& errors)
		{
			auto animation = Ptr(new GuiInstanceGradientAnimation);
			animation->tagPosition = { {resource},xml->rootElement->codeRange.start };

			if (auto classAttr = XmlGetAttribute(xml->rootElement, L"ref.Class"))
			{
				animation->className = classAttr->value.value;
				animation->classPosition = { {resource},classAttr->value.codeRange.start };
				animation->classPosition.column += 1;
			}
			else
			{
				errors.Add({
					{{resource},xml->rootElement->codeRange.start},
					L"Precompile: Missing required attribute: \"ref.Class\"."
					});
			}

			if (auto typeAttr = XmlGetAttribute(xml->rootElement, L"Type"))
			{
				animation->typeName = typeAttr->value.value;
				animation->typePosition = { { resource },typeAttr->value.codeRange.start };
				animation->typePosition.column += 1;
			}
			else
			{
				errors.Add({
					{ { resource },xml->rootElement->codeRange.start },
					L"Precompile: Missing required attribute: \"Type\"."
					});
			}

			if (auto interpolationElement = XmlGetElement(xml->rootElement, L"Interpolation"))
			{
				if (auto cdata = interpolationElement->subNodes[0].Cast<XmlCData>())
				{
					animation->interpolation = cdata->content.value;
					animation->interpolationPosition = { { resource },cdata->codeRange.start };
					animation->interpolationPosition.column += 9; // <![CDATA[
				}
				else
				{
					errors.Add({
						{ { resource },interpolationElement->codeRange.start },
						L"Precompile: Interpolation function should be contained in a CDATA section."
						});
				}
			}

			if (auto targetsElement = XmlGetElement(xml->rootElement, L"Targets"))
			{
				for (auto targetElement : XmlGetElements(targetsElement, L"Target"))
				{
					Target target;

					if (auto nameAttr = XmlGetAttribute(targetElement, L"Name"))
					{
						target.name = nameAttr->value.value;
						target.namePosition = { { resource },nameAttr->value.codeRange.start };
						target.namePosition.column += 1;
					}
					else
					{
						errors.Add({
							{ { resource },targetElement->codeRange.start },
							L"Precompile: Missing required attribute: \"Name\"."
							});
					}

					if (auto interpolationElement = XmlGetElement(targetElement, L"Interpolation"))
					{
						if (auto cdata = interpolationElement->subNodes[0].Cast<XmlCData>())
						{
							target.interpolation = cdata->content.value;
							target.interpolationPosition = { { resource },cdata->codeRange.start };
							target.interpolationPosition.column += 9; // <![CDATA[
						}
						else
						{
							errors.Add({
								{ { resource },interpolationElement->codeRange.start },
								L"Precompile: Interpolation function should be contained in a CDATA section."
								});
						}
					}

					animation->targets.Add(target);
				}

				if (animation->targets.Count() == 0)
				{
					errors.Add({
						{ { resource },targetsElement->codeRange.start },
						L"Precompile: Missing required element: \"Target\" in \"Targets\"."
						});
				}
			}
			else
			{
				errors.Add({
					{ { resource },xml->rootElement->codeRange.start },
					L"Precompile: Missing required element: \"Targets\"."
					});
			}

			return animation;
		}

/***********************************************************************
GuiInstanceGradientAnimation::SaveToXml
***********************************************************************/

		Ptr<glr::xml::XmlElement> GuiInstanceGradientAnimation::SaveToXml()
		{
			auto gradientElement = Ptr(new XmlElement);
			{
				auto classAttr = Ptr(new XmlAttribute);
				classAttr->name.value = L"ref.Class";
				classAttr->value.value = className;
				gradientElement->attributes.Add(classAttr);
			}
			{
				auto typeAttr = Ptr(new XmlAttribute);
				typeAttr->name.value = L"Type";
				typeAttr->value.value = typeName;
				gradientElement->attributes.Add(typeAttr);
			}
			if (interpolation != L"")
			{
				auto interpolationElement = Ptr(new XmlElement);
				interpolationElement->name.value = L"Interpolation";
				gradientElement->subNodes.Add(interpolationElement);

				auto cdata = Ptr(new XmlCData);
				cdata->content.value = interpolation;
				interpolationElement->subNodes.Add(cdata);
			}
			{
				auto targetsElement = Ptr(new XmlElement);
				targetsElement->name.value = L"Targets";
				gradientElement->subNodes.Add(targetsElement);

				for (auto target : targets)
				{
					auto targetElement = Ptr(new XmlElement);
					targetElement->name.value = L"Target";
					targetsElement->subNodes.Add(targetElement);
					{
						auto nameAttr = Ptr(new XmlAttribute);
						nameAttr->name.value = L"Name";
						nameAttr->value.value = target.name;
						targetElement->attributes.Add(nameAttr);
					}
					if (target.interpolation != L"")
					{
						auto interpolationElement = Ptr(new XmlElement);
						interpolationElement->name.value = L"Interpolation";
						targetElement->subNodes.Add(interpolationElement);

						auto cdata = Ptr(new XmlCData);
						cdata->content.value = target.interpolation;
						interpolationElement->subNodes.Add(cdata);
					}
				}
			}
			return gradientElement;
		}

/***********************************************************************
GuiInstanceGradientAnimation::ValidatePropertyType
***********************************************************************/

		bool GuiInstanceGradientAnimation::IsSupportedPrimitiveType(description::ITypeDescriptor* td)
		{
			if (td == description::GetTypeDescriptor<vint8_t>()) return true;
			if (td == description::GetTypeDescriptor<vint16_t>()) return true;
			if (td == description::GetTypeDescriptor<vint32_t>()) return true;
			if (td == description::GetTypeDescriptor<vint64_t>()) return true;
			if (td == description::GetTypeDescriptor<vuint8_t>()) return true;
			if (td == description::GetTypeDescriptor<vuint16_t>()) return true;
			if (td == description::GetTypeDescriptor<vuint32_t>()) return true;
			if (td == description::GetTypeDescriptor<vuint64_t>()) return true;
			if (td == description::GetTypeDescriptor<float>()) return true;
			if (td == description::GetTypeDescriptor<double>()) return true;
			return false;
		}

		vint GuiInstanceGradientAnimation::ValidateStructMembers(GuiResourceTextPos namePosition, description::ITypeDescriptor* td, const WString& prefix, GuiResourceError::List& errors)
		{
			vint members = 0;
			vint count = td->GetPropertyCount();
			for (vint i = 0; i < count; i++)
			{
				auto propInfo = td->GetProperty(i);
				members += ValidatePropertyType(namePosition, propInfo->GetReturn(), prefix + L"." + propInfo->GetName(), errors);
			}

			count = td->GetBaseTypeDescriptorCount();
			for (vint i = 0; i < count; i++)
			{
				members += ValidateStructMembers(namePosition, td->GetBaseTypeDescriptor(i), prefix, errors);
			}

			return members;
		}

		vint GuiInstanceGradientAnimation::ValidatePropertyType(GuiResourceTextPos namePosition, description::ITypeInfo* typeInfo, const WString& prefix, GuiResourceError::List& errors, bool rootValue)
		{
			auto td = typeInfo->GetTypeDescriptor();
			switch (td->GetTypeDescriptorFlags())
			{
			case TypeDescriptorFlags::Primitive:
				if (IsSupportedPrimitiveType(td))
				{
					return 1;
				}
				break;
			case TypeDescriptorFlags::Struct:
				{
					vint members = ValidateStructMembers(namePosition, td, prefix, errors);
					if (rootValue && members == 0)
					{
						errors.Add({ namePosition,L"Precompile: Property \"" + prefix + L"\" of type \"" + typeInfo->GetTypeFriendlyName() + L"\" in class \"" + typeName + L"\" is not supported. A struct should at least has one numeric primitive member to perform gradual changing." });
					}
					return members;
				}
			default:;
			}
			errors.Add({ namePosition,L"Precompile: Property \"" + prefix + L"\" of type \"" + typeInfo->GetTypeFriendlyName() + L"\" in class \"" + typeName + L"\" is not supported. Only numeric types and structs are able to perform gradual changing." });
			return 0;
		}

/***********************************************************************
GuiInstanceGradientAnimation::EnumerateMembers
***********************************************************************/

		void GuiInstanceGradientAnimation::EnumerateMembers(EnumerateMemberCallback callback, EnumerateMemberAccessor accessor, description::IPropertyInfo* propInfo, description::IPropertyInfo* originPropInfo)
		{
			auto td = propInfo->GetReturn()->GetTypeDescriptor();
			auto newAccessor = [=](Ptr<WfExpression> expression)
			{
				auto member = Ptr(new WfMemberExpression);
				member->parent = accessor(expression);
				member->name.value = propInfo->GetName();
				return member;
			};

			switch (td->GetTypeDescriptorFlags())
			{
			case TypeDescriptorFlags::Primitive:
				callback(newAccessor, propInfo, originPropInfo);
				break;
			case TypeDescriptorFlags::Struct:
				EnumerateMembers(callback, newAccessor, td, originPropInfo);
				break;
			default:;
			}
		}

		void GuiInstanceGradientAnimation::EnumerateMembers(EnumerateMemberCallback callback, EnumerateMemberAccessor accessor, description::ITypeDescriptor* td, description::IPropertyInfo* originPropInfo)
		{
			vint count = td->GetPropertyCount();
			for (vint i = 0; i < count; i++)
			{
				auto propInfo = td->GetProperty(i);
				if (propInfo->GetName() == L"value" && propInfo->GetOwnerTypeDescriptor() == description::GetTypeDescriptor<Color>())
				{
					continue;
				}
				EnumerateMembers(callback, accessor, propInfo, originPropInfo);
			}

			count = td->GetBaseTypeDescriptorCount();
			for (vint i = 0; i < count; i++)
			{
				EnumerateMembers(callback, accessor, td->GetBaseTypeDescriptor(i), originPropInfo);
			}
		}

		void GuiInstanceGradientAnimation::EnumerateProperties(EnumerateMemberCallback callback, description::ITypeDescriptor* td)
		{
			for (auto target : targets)
			{
				auto propInfo = td->GetPropertyByName(target.name, true);
				EnumerateMembers(callback, [](auto x) {return x; }, propInfo, propInfo);
			}
		}

/***********************************************************************
GuiInstanceGradientAnimation::InitStruct
***********************************************************************/

		Ptr<workflow::WfExpression> GuiInstanceGradientAnimation::InitStruct(description::IPropertyInfo* propInfo, const WString& prefix, collections::SortedList<WString>& varNames)
		{
			auto td = propInfo->GetReturn()->GetTypeDescriptor();
			auto name = prefix + L"_" + propInfo->GetName();

			if (td->GetTypeDescriptorFlags() == TypeDescriptorFlags::Primitive)
			{
				if (!varNames.Contains(name))
				{
					return nullptr;
				}
				auto ref = Ptr(new WfReferenceExpression);
				ref->name.value = L"<ani>" + name;
				return ref;
			}
			else
			{
				List<ITypeDescriptor*> tds;
				tds.Add(td);
				auto ref = Ptr(new WfConstructorExpression);

				// TODO: (enumerable) foreach:alterable
				for (vint i = 0; i < tds.Count(); i++)
				{
					auto currentTd = tds[i];
					vint count = currentTd->GetBaseTypeDescriptorCount();
					for (vint j = 0; j < count; j++)
					{
						tds.Add(currentTd->GetBaseTypeDescriptor(j));
					}

					count = currentTd->GetPropertyCount();
					for (vint j = 0; j < count; j++)
					{
						auto currentPropInfo = currentTd->GetProperty(j);
						if (auto expr = InitStruct(currentPropInfo, name, varNames))
						{
							auto pair = Ptr(new WfConstructorArgument);

							auto refName = Ptr(new WfReferenceExpression);
							refName->name.value = currentPropInfo->GetName();

							pair->key = refName;
							pair->value = expr;
							ref->arguments.Add(pair);
						}
					}
				}

				return ref;
			}
		}

/***********************************************************************
GuiInstanceGradientAnimation::Compile
***********************************************************************/

		Ptr<workflow::WfModule> GuiInstanceGradientAnimation::Compile(GuiResourcePrecompileContext& precompileContext, const WString& moduleName, bool generateImpl, GuiResourceError::List& errors)
		{
			if (auto td = description::GetTypeDescriptor(typeName))
			{
				if (td->GetTypeDescriptorFlags() == TypeDescriptorFlags::Class)
				{
					{
						if (auto ctorGroup = td->GetConstructorGroup())
						{
							vint count = ctorGroup->GetMethodCount();
							for (vint i = 0; i < count; i++)
							{
								auto ctor = ctorGroup->GetMethod(i);
								if (ctor->GetReturn()->GetDecorator() == ITypeInfo::SharedPtr && ctor->GetParameterCount() == 0)
								{
									goto CTOR_CHECK_PASS;
								}
							}
						}
						errors.Add({ typePosition,L"Precompile: Class \"" + typeName + L"\" should have a default constructor which returns a shared pointer and has no arguments." });
					CTOR_CHECK_PASS:;
					}

					auto module = Ptr(new WfModule);
					module->moduleType = WfModuleType::Module;
					module->name.value = moduleName;
					auto animationClass = Workflow_InstallClass(className, module);

					auto typeInfo = Ptr(new SharedPtrTypeInfo(Ptr(new TypeDescriptorTypeInfo(td, TypeInfoHint::Normal))));
					auto typeInfoDouble = CreateTypeInfoFromTypeFlag(TypeFlag::F8);

					auto notImplemented = []()
					{
						auto block = Ptr(new WfBlockStatement);

						auto stringExpr = Ptr(new WfStringExpression);
						stringExpr->value.value = L"Not Implemented";

						auto raiseStat = Ptr(new WfRaiseExceptionStatement);
						raiseStat->expression = stringExpr;

						block->statements.Add(raiseStat);
						return block;
					};

					{
						// prop Begin : <TYPE> = <DEFAULT> {}
						auto prop = Ptr(new WfAutoPropertyDeclaration);
						animationClass->declarations.Add(prop);

						prop->functionKind = WfFunctionKind::Normal;
						prop->name.value = L"Begin";
						prop->type = GetTypeFromTypeInfo(typeInfo.Obj());
						prop->expression = CreateDefaultValue(typeInfo.Obj());
						prop->configConst = WfAPConst::Writable;
						prop->configObserve = WfAPObserve::Observable;
					}
					{
						// prop End : <TYPE> = <DEFAULT> {}
						auto prop = Ptr(new WfAutoPropertyDeclaration);
						animationClass->declarations.Add(prop);

						prop->functionKind = WfFunctionKind::Normal;
						prop->name.value = L"End";
						prop->type = GetTypeFromTypeInfo(typeInfo.Obj());
						prop->expression = CreateDefaultValue(typeInfo.Obj());
						prop->configConst = WfAPConst::Writable;
						prop->configObserve = WfAPObserve::Observable;
					}
					{
						// prop Current : <TYPE> = <DEFAULT> {}
						auto prop = Ptr(new WfAutoPropertyDeclaration);
						animationClass->declarations.Add(prop);

						prop->functionKind = WfFunctionKind::Normal;
						prop->name.value = L"Current";
						prop->type = GetTypeFromTypeInfo(typeInfo.Obj());
						prop->expression = CreateDefaultValue(typeInfo.Obj());
						prop->configConst = WfAPConst::Writable;
						prop->configObserve = WfAPObserve::Observable;
					}

					auto createIntVar = [&](const WString& name, const WString& interpolation, GuiResourceTextPos interpolationPosition)
					{
						// prop <ani-int> : (func(double):double) = <VALUE> {const, not observe}
						auto var = Ptr(new WfVariableDeclaration);
						animationClass->declarations.Add(var);

						auto att = Ptr(new WfAttribute);
						att->category.value = L"cpp";
						att->name.value = L"Private";
						var->attributes.Add(att);

						var->name.value = L"<ani-int>" + name;
						var->type = GetTypeFromTypeInfo(TypeInfoRetriver<Func<double(double)>>::CreateTypeInfo().Obj());
						if (interpolation == L"" || !generateImpl)
						{
							auto ref = Ptr(new WfOrderedNameExpression);
							ref->name.value = L"$1";

							auto lambda = Ptr(new WfOrderedLambdaExpression);
							lambda->body = ref;

							var->expression = lambda;
						}
						else
						{
							var->expression = Workflow_ParseExpression(precompileContext, interpolationPosition.originalLocation, interpolation, interpolationPosition, errors);
						}
					};
					createIntVar(L"", interpolation, interpolationPosition);
					for (auto target : targets)
					{
						if (target.interpolation != L"")
						{
							createIntVar(target.name, target.interpolation, target.interpolationPosition);
						}
					}

					List<IPropertyInfo*> props;
					List<Ptr<WfExpression>> interpolations;
					for (auto target : targets)
					{
						if (auto propInfo = td->GetPropertyByName(target.name, true))
						{
							if (!propInfo->GetGetter())
							{
								errors.Add({ target.namePosition,L"Precompile: Variable \"" + target.name + L"\" is not supported. An writable property with event is expected." });
							}
							else if (!propInfo->GetSetter())
							{
								errors.Add({ target.namePosition,L"Precompile: Readonly property \"" + target.name + L"\" is not supported. An writable property with event is expected." });
							}
							else if (!propInfo->GetValueChangedEvent())
							{
								errors.Add({ target.namePosition,L"Precompile: Property \"" + target.name + L"\" is not supported. An writable property with event is expected." });
							}
							ValidatePropertyType(target.namePosition, propInfo->GetReturn(), propInfo->GetName(), errors, true);

							Ptr<WfExpression> interpolation;
							if (target.interpolation != L"" && generateImpl)
							{
								interpolation = Workflow_ParseExpression(precompileContext, target.interpolationPosition.originalLocation, target.interpolation, target.interpolationPosition, errors);
							}

							props.Add(propInfo);
							interpolations.Add(interpolation);
						}
						else
						{
							errors.Add({ target.namePosition,L"Precompile: Property \"" + target.name + L"\" does not exist." });
						}
					}

					{
						// func GetTimeScale(<ani>begin : <TYPE>, <ani>end : <TYPE>, <ani>current : <TYPE>) : double
						auto func = Ptr(new WfFunctionDeclaration);
						animationClass->declarations.Add(func);

						func->functionKind = WfFunctionKind::Normal;
						func->anonymity = WfFunctionAnonymity::Named;
						func->name.value = L"GetTimeScale";
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<ani>begin";
							argument->type = GetTypeFromTypeInfo(typeInfo.Obj());
							func->arguments.Add(argument);
						}
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<ani>end";
							argument->type = GetTypeFromTypeInfo(typeInfo.Obj());
							func->arguments.Add(argument);
						}
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<ani>current";
							argument->type = GetTypeFromTypeInfo(typeInfo.Obj());
							func->arguments.Add(argument);
						}
						func->returnType = GetTypeFromTypeInfo(typeInfoDouble.Obj());

						if (generateImpl)
						{
							auto block = Ptr(new WfBlockStatement);
							func->statement = block;
							{
								auto refZero = Ptr(new WfFloatingExpression);
								refZero->value.value = L"0.0";

								auto varScale = Ptr(new WfVariableDeclaration);
								varScale->name.value = L"<ani>scale";
								varScale->expression = refZero;

								auto declStat = Ptr(new WfVariableStatement);
								declStat->variable = varScale;
								block->statements.Add(declStat);
							}
							EnumerateProperties([&](EnumerateMemberAccessor accessor, description::IPropertyInfo*, description::IPropertyInfo* propInfo)
							{
								auto subBlock = Ptr(new WfBlockStatement);
								block->statements.Add(subBlock);

								auto createVariable = [=](const WString& first, const WString& second, const WString& variable)
								{
									auto refBegin = Ptr(new WfReferenceExpression);
									refBegin->name.value = first;

									auto firstExpr = Ptr(new WfTypeCastingExpression);
									firstExpr->expression = accessor(refBegin);
									firstExpr->type = GetTypeFromTypeInfo(TypeInfoRetriver<double>::CreateTypeInfo().Obj());
									firstExpr->strategy = WfTypeCastingStrategy::Strong;

									auto refEnd = Ptr(new WfReferenceExpression);
									refEnd->name.value = second;

									auto secondExpr = Ptr(new WfTypeCastingExpression);
									secondExpr->expression = accessor(refEnd);
									secondExpr->type = GetTypeFromTypeInfo(TypeInfoRetriver<double>::CreateTypeInfo().Obj());
									secondExpr->strategy = WfTypeCastingStrategy::Strong;

									auto subExpr = Ptr(new WfBinaryExpression);
									subExpr->first = firstExpr;
									subExpr->second = secondExpr;
									subExpr->op = WfBinaryOperator::Sub;

									auto refAbs = Ptr(new WfChildExpression);
									refAbs->parent = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<Math>());
									refAbs->name.value = L"Abs";

									auto callExpr = Ptr(new WfCallExpression);
									callExpr->function = refAbs;
									callExpr->arguments.Add(subExpr);

									auto varRef = Ptr(new WfVariableDeclaration);
									varRef->name.value = variable;
									varRef->expression = callExpr;

									auto declStat = Ptr(new WfVariableStatement);
									declStat->variable = varRef;
									subBlock->statements.Add(declStat);
								};
								createVariable(L"<ani>begin", L"<ani>end", L"<ani>ref");
								createVariable(L"<ani>current", L"<ani>end", L"<ani>cur");
								{
									auto refRef = Ptr(new WfReferenceExpression);
									refRef->name.value = L"<ani>ref";

									auto refEpsilon = Ptr(new WfFloatingExpression);
									refEpsilon->value.value = L"0.000001";

									auto refMaxEpsilon = Ptr(new WfChildExpression);
									refMaxEpsilon->parent = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<Math>());
									refMaxEpsilon->name.value = L"Max";

									auto callExprEpsilon = Ptr(new WfCallExpression);
									callExprEpsilon->function = refMaxEpsilon;
									callExprEpsilon->arguments.Add(refRef);
									callExprEpsilon->arguments.Add(refEpsilon);

									auto refCur = Ptr(new WfReferenceExpression);
									refCur->name.value = L"<ani>cur";

									auto divExpr = Ptr(new WfBinaryExpression);
									divExpr->first = refCur;
									divExpr->second = callExprEpsilon;
									divExpr->op = WfBinaryOperator::Div;

									auto refMax = Ptr(new WfChildExpression);
									refMax->parent = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<Math>());
									refMax->name.value = L"Max";

									auto refScale = Ptr(new WfReferenceExpression);
									refScale->name.value = L"<ani>scale";

									auto callExpr = Ptr(new WfCallExpression);
									callExpr->function = refMax;
									callExpr->arguments.Add(refScale);
									callExpr->arguments.Add(divExpr);

									auto refScale2 = Ptr(new WfReferenceExpression);
									refScale2->name.value = L"<ani>scale";

									auto assignExpr = Ptr(new WfBinaryExpression);
									assignExpr->first = refScale2;
									assignExpr->second = callExpr;
									assignExpr->op = WfBinaryOperator::Assign;

									auto exprStat = Ptr(new WfExpressionStatement);
									exprStat->expression = assignExpr;

									subBlock->statements.Add(exprStat);
								}
							}, td);
							{
								auto refOne = Ptr(new WfFloatingExpression);
								refOne->value.value = L"1.0";

								auto refScale = Ptr(new WfReferenceExpression);
								refScale->name.value = L"<ani>scale";

								auto refMin = Ptr(new WfChildExpression);
								refMin->parent = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<Math>());
								refMin->name.value = L"Min";

								auto callExpr = Ptr(new WfCallExpression);
								callExpr->function = refMin;
								callExpr->arguments.Add(refOne);
								callExpr->arguments.Add(refScale);

								auto returnStat = Ptr(new WfReturnStatement);
								returnStat->expression = callExpr;
								block->statements.Add(returnStat);
							}
						}
						else
						{
							func->statement = notImplemented();
						}
					}
					{
						// func Interpolate(<ani>begin : <TYPE>, <ani>end : <TYPE>, <ani>current : <TYPE>, <ani>ratio : double) : void
						auto func = Ptr(new WfFunctionDeclaration);
						animationClass->declarations.Add(func);

						func->functionKind = WfFunctionKind::Normal;
						func->anonymity = WfFunctionAnonymity::Named;
						func->name.value = L"Interpolate";
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<ani>begin";
							argument->type = GetTypeFromTypeInfo(typeInfo.Obj());
							func->arguments.Add(argument);
						}
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<ani>end";
							argument->type = GetTypeFromTypeInfo(typeInfo.Obj());
							func->arguments.Add(argument);
						}
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<ani>current";
							argument->type = GetTypeFromTypeInfo(typeInfo.Obj());
							func->arguments.Add(argument);
						}
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<ani>ratio";
							argument->type = GetTypeFromTypeInfo(typeInfoDouble.Obj());
							func->arguments.Add(argument);
						}
						func->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<void>::CreateTypeInfo().Obj());

						if (generateImpl)
						{
							auto block = Ptr(new WfBlockStatement);
							func->statement = block;

							SortedList<WString> varNames;

							EnumerateProperties([&](EnumerateMemberAccessor accessor, description::IPropertyInfo* propInfo, description::IPropertyInfo* originPropInfo)
							{
								WString intFunc = L"<ani-int>";
								if (From(targets).Any([=](const Target& target)
									{
										return target.name == originPropInfo->GetName() && target.interpolation != L"";
									}))
								{
									intFunc += originPropInfo->GetName();
								}

								Ptr<WfExpression> part1, part2, propChain;
								{
									auto refParent = Ptr(new WfReferenceExpression);
									refParent->name.value = L"<ani>begin";

									auto refProp = Ptr(new WfTypeCastingExpression);
									refProp->expression = (propChain = accessor(refParent));
									refProp->type = GetTypeFromTypeInfo(TypeInfoRetriver<double>::CreateTypeInfo().Obj());
									refProp->strategy = WfTypeCastingStrategy::Strong;

									auto refOne = Ptr(new WfFloatingExpression);
									refOne->value.value = L"1.0";

									auto refInt = Ptr(new WfReferenceExpression);
									refInt->name.value = intFunc;

									auto refRatio = Ptr(new WfReferenceExpression);
									refRatio->name.value = L"<ani>ratio";

									auto callExpr = Ptr(new WfCallExpression);
									callExpr->function = refInt;
									callExpr->arguments.Add(refRatio);

									auto subExpr = Ptr(new WfBinaryExpression);
									subExpr->first = refOne;
									subExpr->second = callExpr;
									subExpr->op = WfBinaryOperator::Sub;

									auto mulExpr = Ptr(new WfBinaryExpression);
									mulExpr->first = refProp;
									mulExpr->second = subExpr;
									mulExpr->op = WfBinaryOperator::Mul;

									part1 = mulExpr;
								}
								{
									auto refParent = Ptr(new WfReferenceExpression);
									refParent->name.value = L"<ani>end";

									auto refProp = Ptr(new WfTypeCastingExpression);
									refProp->expression = accessor(refParent);
									refProp->type = GetTypeFromTypeInfo(TypeInfoRetriver<double>::CreateTypeInfo().Obj());
									refProp->strategy = WfTypeCastingStrategy::Strong;

									auto refInt = Ptr(new WfReferenceExpression);
									refInt->name.value = intFunc;

									auto refRatio = Ptr(new WfReferenceExpression);
									refRatio->name.value = L"<ani>ratio";

									auto callExpr = Ptr(new WfCallExpression);
									callExpr->function = refInt;
									callExpr->arguments.Add(refRatio);

									auto mulExpr = Ptr(new WfBinaryExpression);
									mulExpr->first = refProp;
									mulExpr->second = callExpr;
									mulExpr->op = WfBinaryOperator::Mul;

									part2 = mulExpr;
								}

								Ptr<WfExpression> exprMixed;
								{
									auto addExpr = Ptr(new WfBinaryExpression);
									addExpr->first = part1;
									addExpr->second = part2;
									addExpr->op = WfBinaryOperator::Add;

									if (propInfo->GetReturn()->GetTypeDescriptor() == description::GetTypeDescriptor<double>())
									{
										exprMixed = addExpr;
									}
									else if(propInfo->GetReturn()->GetTypeDescriptor() == description::GetTypeDescriptor<double>())
									{
										exprMixed = addExpr;
									}
									else
									{
										auto refRound = Ptr(new WfChildExpression);
										refRound->parent = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<Math>());
										refRound->name.value = L"Round";

										auto callRoundExpr = Ptr(new WfCallExpression);
										callRoundExpr->function = refRound;
										callRoundExpr->arguments.Add(addExpr);

										exprMixed = callRoundExpr;
									}
								}

								auto castExpr = Ptr(new WfTypeCastingExpression);
								castExpr->expression = exprMixed;
								castExpr->type = GetTypeFromTypeInfo(propInfo->GetReturn());
								castExpr->strategy = WfTypeCastingStrategy::Strong;

								auto varRef = Ptr(new WfVariableDeclaration);
								{
									WString name = L"";
									while (auto member = propChain.Cast<WfMemberExpression>())
									{
										name = L"_" + member->name.value + name;
										propChain = member->parent;
									}
									varNames.Add(name);
									varRef->name.value = L"<ani>" + name;
								}
								varRef->expression = castExpr;

								auto declStat = Ptr(new WfVariableStatement);
								declStat->variable = varRef;
								block->statements.Add(declStat);
							}, td);

							for (auto target : targets)
							{
								auto refCurrent = Ptr(new WfReferenceExpression);
								refCurrent->name.value = L"<ani>current";

								auto refProp = Ptr(new WfMemberExpression);
								refProp->parent = refCurrent;
								refProp->name.value = target.name;

								auto assignExpr = Ptr(new WfBinaryExpression);
								assignExpr->first = refProp;
								assignExpr->second = InitStruct(td->GetPropertyByName(target.name, true), L"", varNames);
								assignExpr->op = WfBinaryOperator::Assign;

								auto exprStat = Ptr(new WfExpressionStatement);
								exprStat->expression = assignExpr;
								block->statements.Add(exprStat);
							}
						}
						else
						{
							func->statement = notImplemented();
						}
					}
					{
						// func Interpolate(<ani>ratio : double) : void
						auto func = Ptr(new WfFunctionDeclaration);
						animationClass->declarations.Add(func);

						func->functionKind = WfFunctionKind::Normal;
						func->anonymity = WfFunctionAnonymity::Named;
						func->name.value = L"Interpolate";
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<ani>ratio";
							argument->type = GetTypeFromTypeInfo(typeInfoDouble.Obj());
							func->arguments.Add(argument);
						}
						func->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<void>::CreateTypeInfo().Obj());

						if (generateImpl)
						{
							auto block = Ptr(new WfBlockStatement);
							func->statement = block;

							auto refBegin = Ptr(new WfReferenceExpression);
							refBegin->name.value = L"Begin";

							auto refEnd = Ptr(new WfReferenceExpression);
							refEnd->name.value = L"End";

							auto refCurrent = Ptr(new WfReferenceExpression);
							refCurrent->name.value = L"Current";

							auto refRatio = Ptr(new WfReferenceExpression);
							refRatio->name.value = L"<ani>ratio";

							auto refFunc = Ptr(new WfReferenceExpression);
							refFunc->name.value = L"Interpolate";

							auto callExpr = Ptr(new WfCallExpression);
							callExpr->function = refFunc;
							callExpr->arguments.Add(refBegin);
							callExpr->arguments.Add(refEnd);
							callExpr->arguments.Add(refCurrent);
							callExpr->arguments.Add(refRatio);

							auto exprStat = Ptr(new WfExpressionStatement);
							exprStat->expression = callExpr;

							block->statements.Add(exprStat);
						}
						else
						{
							func->statement = notImplemented();
						}
					}
					{
						// func CreateAnimation(<ani>target : <TYPE>, <ani>time : UInt64) : IGuiAnimation^
						auto func = Ptr(new WfFunctionDeclaration);
						animationClass->declarations.Add(func);

						func->functionKind = WfFunctionKind::Normal;
						func->anonymity = WfFunctionAnonymity::Named;
						func->name.value = L"CreateAnimation";
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<ani>target";
							argument->type = GetTypeFromTypeInfo(typeInfo.Obj());
							func->arguments.Add(argument);
						}
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<ani>time";
							argument->type = GetTypeFromTypeInfo(TypeInfoRetriver<vuint64_t>::CreateTypeInfo().Obj());
							func->arguments.Add(argument);
						}
						func->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<Ptr<IGuiAnimation>>::CreateTypeInfo().Obj());

						if (generateImpl)
						{
							auto block = Ptr(new WfBlockStatement);
							func->statement = block;

							{
								auto refEnd = Ptr(new WfReferenceExpression);
								refEnd->name.value = L"End";

								auto refTarget = Ptr(new WfReferenceExpression);
								refTarget->name.value = L"<ani>target";

								auto refCurrent = Ptr(new WfReferenceExpression);
								refCurrent->name.value = L"Current";

								auto refFunc = Ptr(new WfReferenceExpression);
								refFunc->name.value = L"GetTimeScale";

								auto callExpr = Ptr(new WfCallExpression);
								callExpr->function = refFunc;
								callExpr->arguments.Add(refEnd);
								callExpr->arguments.Add(refTarget);
								callExpr->arguments.Add(refCurrent);

								auto refTime = Ptr(new WfReferenceExpression);
								refTime->name.value = L"<ani>time";

								auto mulExpr = Ptr(new WfBinaryExpression);
								mulExpr->first = refTime;
								mulExpr->second = callExpr;
								mulExpr->op = WfBinaryOperator::Mul;

								auto refRound = Ptr(new WfChildExpression);
								refRound->parent = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<Math>());
								refRound->name.value = L"Round";

								auto callRoundExpr = Ptr(new WfCallExpression);
								callRoundExpr->function = refRound;
								callRoundExpr->arguments.Add(mulExpr);

								auto castExpr = Ptr(new WfTypeCastingExpression);
								castExpr->type = GetTypeFromTypeInfo(TypeInfoRetriver<vuint64_t>::CreateTypeInfo().Obj());
								castExpr->expression = callRoundExpr;
								castExpr->strategy = WfTypeCastingStrategy::Strong;

								auto varDecl = Ptr(new WfVariableDeclaration);
								varDecl->name.value = L"<ani>scaledTime";
								varDecl->expression = castExpr;

								auto varStat = Ptr(new WfVariableStatement);
								varStat->variable = varDecl;
								block->statements.Add(varStat);
							}
							{
								for (auto target : targets)
								{
									auto refBegin = Ptr(new WfReferenceExpression);
									refBegin->name.value = L"Begin";

									auto refBeginProp = Ptr(new WfMemberExpression);
									refBeginProp->parent = refBegin;
									refBeginProp->name.value = target.name;

									auto refCurrent = Ptr(new WfReferenceExpression);
									refCurrent->name.value = L"Current";

									auto refCurrentProp = Ptr(new WfMemberExpression);
									refCurrentProp->parent = refCurrent;
									refCurrentProp->name.value = target.name;

									auto assignExpr = Ptr(new WfBinaryExpression);
									assignExpr->first = refBeginProp;
									assignExpr->second = refCurrentProp;
									assignExpr->op = WfBinaryOperator::Assign;

									auto exprStat = Ptr(new WfExpressionStatement);
									exprStat->expression = assignExpr;

									block->statements.Add(exprStat);
								}
							}
							{
								auto refEnd = Ptr(new WfReferenceExpression);
								refEnd->name.value = L"End";

								auto refTarget = Ptr(new WfReferenceExpression);
								refTarget->name.value = L"<ani>target";

								auto assignExpr = Ptr(new WfBinaryExpression);
								assignExpr->first = refEnd;
								assignExpr->second = refTarget;
								assignExpr->op = WfBinaryOperator::Assign;

								auto exprStat = Ptr(new WfExpressionStatement);
								exprStat->expression = assignExpr;

								block->statements.Add(exprStat);
							}
							{
								auto refCA = Ptr(new WfChildExpression);
								refCA->parent = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<IGuiAnimation>());
								refCA->name.value = L"CreateAnimation";

								auto funcExpr = Ptr(new WfFunctionExpression);
								{
									auto funcDecl = Ptr(new WfFunctionDeclaration);
									funcExpr->function = funcDecl;

									funcDecl->functionKind = WfFunctionKind::Normal;
									funcDecl->anonymity = WfFunctionAnonymity::Anonymous;
									{
										auto argument = Ptr(new WfFunctionArgument);
										argument->name.value = L"<ani>currentTime";
										argument->type = GetTypeFromTypeInfo(TypeInfoRetriver<vuint64_t>::CreateTypeInfo().Obj());
										funcDecl->arguments.Add(argument);
									}
									funcDecl->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<void>::CreateTypeInfo().Obj());

									auto subBlock = Ptr(new WfBlockStatement);
									funcDecl->statement = subBlock;

									{
										auto refCurrentTime = Ptr(new WfReferenceExpression);
										refCurrentTime->name.value = L"<ani>currentTime";

										auto firstExpr = Ptr(new WfTypeCastingExpression);
										firstExpr->expression = refCurrentTime;
										firstExpr->type = GetTypeFromTypeInfo(TypeInfoRetriver<double>::CreateTypeInfo().Obj());
										firstExpr->strategy = WfTypeCastingStrategy::Strong;

										auto refTime = Ptr(new WfReferenceExpression);
										refTime->name.value = L"<ani>time";

										auto secondExpr = Ptr(new WfTypeCastingExpression);
										secondExpr->expression = refTime;
										secondExpr->type = GetTypeFromTypeInfo(TypeInfoRetriver<double>::CreateTypeInfo().Obj());
										secondExpr->strategy = WfTypeCastingStrategy::Strong;

										auto divExpr = Ptr(new WfBinaryExpression);
										divExpr->first = firstExpr;
										divExpr->second = secondExpr;
										divExpr->op = WfBinaryOperator::Div;

										auto refInt = Ptr(new WfReferenceExpression);
										refInt->name.value = L"Interpolate";

										auto callExpr = Ptr(new WfCallExpression);
										callExpr->function = refInt;
										callExpr->arguments.Add(divExpr);

										auto exprStat = Ptr(new WfExpressionStatement);
										exprStat->expression = callExpr;

										subBlock->statements.Add(exprStat);
									}
								}

								auto refTime = Ptr(new WfReferenceExpression);
								refTime->name.value = L"<ani>time";

								auto callExpr = Ptr(new WfCallExpression);
								callExpr->function = refCA;
								callExpr->arguments.Add(funcExpr);
								callExpr->arguments.Add(refTime);

								auto returnStat = Ptr(new WfReturnStatement);
								returnStat->expression = callExpr;

								block->statements.Add(returnStat);
							}
						}
						else
						{
							func->statement = notImplemented();
						}
					}
					{
						// new (<ani>current : <TYPE>)
						auto func = Ptr(new WfConstructorDeclaration);
						animationClass->declarations.Add(func);

						func->constructorType = WfConstructorType::SharedPtr;
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<ani>current";
							argument->type = GetTypeFromTypeInfo(typeInfo.Obj());
							func->arguments.Add(argument);
						}

						if (generateImpl)
						{
							auto block = Ptr(new WfBlockStatement);
							func->statement = block;

							{
								List<WString> propNames;
								propNames.Add(L"Begin");
								propNames.Add(L"End");
								propNames.Add(L"Current");

								for (auto propName : propNames)
								{
									{
										auto newExpr = Ptr(new WfNewClassExpression);
										newExpr->type = GetTypeFromTypeInfo(typeInfo.Obj());

										auto refProp = Ptr(new WfReferenceExpression);
										refProp->name.value = propName;

										auto assignExpr = Ptr(new WfBinaryExpression);
										assignExpr->first = refProp;
										assignExpr->second = newExpr;
										assignExpr->op = WfBinaryOperator::Assign;

										auto exprStat = Ptr(new WfExpressionStatement);
										exprStat->expression = assignExpr;

										block->statements.Add(exprStat);
									}
									
									for (auto target : targets)
									{
										auto refProp = Ptr(new WfReferenceExpression);
										refProp->name.value = propName;

										auto refPropProp = Ptr(new WfMemberExpression);
										refPropProp->parent = refProp;
										refPropProp->name.value = target.name;

										auto refCurrent = Ptr(new WfReferenceExpression);
										refCurrent->name.value = L"<ani>current";

										auto refCurrentProp = Ptr(new WfMemberExpression);
										refCurrentProp->parent = refCurrent;
										refCurrentProp->name.value = target.name;

										auto assignExpr = Ptr(new WfBinaryExpression);
										assignExpr->first = refPropProp;
										assignExpr->second = refCurrentProp;
										assignExpr->op = WfBinaryOperator::Assign;

										auto exprStat = Ptr(new WfExpressionStatement);
										exprStat->expression = assignExpr;

										block->statements.Add(exprStat);
									}
								}
							}
						}
						else
						{
							func->statement = notImplemented();
						}
					}

					return module;
				}
				else
				{
					errors.Add({ typePosition, L"Precompile: Type \"" + typeName + L"\" is not a class." });
				}
			}
			else
			{
				errors.Add({ typePosition, L"Precompile: Type \"" + typeName + L"\" does not exist." });
			}

			return nullptr;
		}
	}
}


/***********************************************************************
.\GUIINSTANCELOADER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace glr ::xml;
		using namespace controls;
		using namespace regex;
		using namespace reflection::description;
		using namespace stream;
		using namespace workflow;
		using namespace workflow::analyzer;
		using namespace workflow::typeimpl;

/***********************************************************************
GuiInstancePropertyInfo
***********************************************************************/

		Ptr<GuiInstancePropertyInfo> GuiInstancePropertyInfo::Unsupported()
		{
			return Ptr(new GuiInstancePropertyInfo);
		}

		Ptr<GuiInstancePropertyInfo> GuiInstancePropertyInfo::Assign(Ptr<description::ITypeInfo> typeInfo)
		{
			auto info = Ptr(new GuiInstancePropertyInfo);
			info->support = SupportAssign;
			if (typeInfo) info->acceptableTypes.Add(typeInfo);
			return info;
		}

		Ptr<GuiInstancePropertyInfo> GuiInstancePropertyInfo::AssignWithParent(Ptr<description::ITypeInfo> typeInfo)
		{
			auto info = Assign(typeInfo);
			info->mergability = MergeWithParent;
			return info;
		}

		Ptr<GuiInstancePropertyInfo> GuiInstancePropertyInfo::Collection(Ptr<description::ITypeInfo> typeInfo)
		{
			auto info = Assign(typeInfo);
			info->support = SupportCollection;
			return info;
		}

		Ptr<GuiInstancePropertyInfo> GuiInstancePropertyInfo::CollectionWithParent(Ptr<description::ITypeInfo> typeInfo)
		{
			auto info = Collection(typeInfo);
			info->mergability = MergeWithParent;
			return info;
		}

		Ptr<GuiInstancePropertyInfo> GuiInstancePropertyInfo::Set(Ptr<description::ITypeInfo> typeInfo)
		{
			auto info = Ptr(new GuiInstancePropertyInfo);
			info->support = SupportSet;
			if (typeInfo) info->acceptableTypes.Add(typeInfo);
			return info;
		}

		Ptr<GuiInstancePropertyInfo> GuiInstancePropertyInfo::Array(Ptr<description::ITypeInfo> typeInfo)
		{
			auto info = Ptr(new GuiInstancePropertyInfo);
			info->support = SupportArray;
			if (typeInfo) info->acceptableTypes.Add(typeInfo);
			return info;
		}

/***********************************************************************
IGuiInstanceLoader
***********************************************************************/

		void IGuiInstanceLoader::ClearReflectionCache()
		{
		}

		void IGuiInstanceLoader::GetRequiredPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)
		{
		}

		void IGuiInstanceLoader::GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)
		{
		}

		void IGuiInstanceLoader::GetPairedProperties(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo, collections::List<GlobalStringKey>& propertyNames)
		{
		}

		Ptr<GuiInstancePropertyInfo> IGuiInstanceLoader::GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)
		{
			return nullptr;
		}

		bool IGuiInstanceLoader::CanCreate(const TypeInfo& typeInfo)
		{
			return false;
		}

		Ptr<workflow::WfBaseConstructorCall> IGuiInstanceLoader::CreateRootInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, ArgumentMap& arguments, GuiResourceError::List& errors)
		{
			CHECK_FAIL(L"IGuiInstanceLoader::CreateRootInstance(GuiResourcePrecompileContext&, types::ResolvingResult&, const TypeInfo&, Ptr<workflow::WfExpression>, ArgumentMap&, GuiResourceError::List&)#This function is not implemented.");
		}

		Ptr<workflow::WfStatement> IGuiInstanceLoader::InitializeRootInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceError::List& errors)
		{
			return nullptr;
		}

		Ptr<workflow::WfStatement> IGuiInstanceLoader::CreateInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)
		{
			CHECK_FAIL(L"IGuiInstanceLoader::CreateInstance(GuiResourcePrecompileContext&, types::ResolvingResult&, const TypeInfo&, GlobalStringKey, ArgumentMap&, GuiResourceTextPos, GuiResourceError::List&)#This function is not implemented.");
		}

		Ptr<workflow::WfStatement> IGuiInstanceLoader::AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)
		{
			CHECK_FAIL(L"IGuiInstanceLoader::AssignParameters(GuiResourcePrecompileContext&, types::ResolvingResult&, const TypeInfo&, GlobalStringKey, ArgumentMap&, GuiResourceTextPos, GuiResourceError::List&)#This function is not implemented.");
		}

		Ptr<workflow::WfExpression> IGuiInstanceLoader::GetParameter(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const PropertyInfo& propertyInfo, GlobalStringKey variableName, GuiResourceTextPos attPosition, GuiResourceError::List& errors)
		{
			CHECK_FAIL(L"IGuiInstanceLoader::GetParameter(GuiResourcePrecompileContext&, types::ResolvingResult&, const PropertyInfo&, GlobalStringKey, GuiResourceTextPos, GuiResourceError::List&)#This function is not implemented.");
		}

/***********************************************************************
GuiInstanceContext::ElementName Parser
***********************************************************************/

		class GuiInstanceContextElementNameParser : public Object, public IGuiParser<GuiInstanceContext::ElementName>
		{
			typedef GuiInstanceContext::ElementName			ElementName;
		public:
			Regex						regexElementName;
			const vint					_namespaceName;
			const vint					_category;
			const vint					_name;
			const vint					_binding;

			GuiInstanceContextElementNameParser()
				: regexElementName(L"((<namespaceName>[a-zA-Z_]/w*):)?((<category>[a-zA-Z_]/w*).)?(<name>[a-zA-Z_]/w*)(-(<binding>[a-zA-Z_]/w*))?")
				, _namespaceName(regexElementName.CaptureNames().IndexOf(L"namespaceName"))
				, _category(regexElementName.CaptureNames().IndexOf(L"category"))
				, _name(regexElementName.CaptureNames().IndexOf(L"name"))
				, _binding(regexElementName.CaptureNames().IndexOf(L"binding"))
			{
			}

			Ptr<ElementName> ParseInternal(const WString& text, collections::List<glr::ParsingError>& errors)override
			{
				Ptr<RegexMatch> match = regexElementName.MatchHead(text);
				if (!match || match->Result().Length() != text.Length())
				{
					glr::ParsingError error;
					error.message = L"Failed to parse an element name \"" + text + L"\".";
					errors.Add(error);
					return nullptr;
				}

				auto elementName = Ptr(new ElementName);
				if (match->Groups().Keys().Contains(_namespaceName))
				{
					elementName->namespaceName = match->Groups()[_namespaceName][0].Value();
				}
				if (match->Groups().Keys().Contains(_category))
				{
					elementName->category = match->Groups()[_category][0].Value();
				}
				if (match->Groups().Keys().Contains(_name))
				{
					elementName->name = match->Groups()[_name][0].Value();
				}
				if (match->Groups().Keys().Contains(_binding))
				{
					elementName->binding = match->Groups()[_binding][0].Value();
				}
				return elementName;
			}
		};

/***********************************************************************
GuiDefaultInstanceLoader
***********************************************************************/

#define CTOR_PARAM_PREFIX\
		static const wchar_t Prefix[] = L"<ctor-parameter>";\
		static const vint PrefixLength = (vint)sizeof(Prefix) / sizeof(*Prefix) - 1;\

#define CTOR_PARAM_NAME(NAME) (NAME).Right((NAME).Length() - PrefixLength)

		class GuiDefaultInstanceLoader : public Object, public IGuiInstanceLoader
		{
		protected:
			typedef Tuple<ITypeDescriptor*, GlobalStringKey>				FieldKey;
			typedef Tuple<Ptr<GuiInstancePropertyInfo>, IPropertyInfo*>		PropertyType;

			Dictionary<FieldKey, PropertyType>								propertyTypes;
			Dictionary<ITypeDescriptor*, IMethodInfo*>						defaultConstructors;
			Dictionary<ITypeDescriptor*, IMethodInfo*>						instanceConstructors;
		public:
			IMethodInfo* GetDefaultConstructor(ITypeDescriptor* typeDescriptor)
			{
				IMethodInfo* ctor = nullptr;
				vint index = defaultConstructors.Keys().IndexOf(typeDescriptor);
				if (index == -1)
				{
					if (auto ctors = typeDescriptor->GetConstructorGroup())
					{
						vint count = ctors->GetMethodCount();
						for (vint i = 0; i < count; i++)
						{
							IMethodInfo* method = ctors->GetMethod(i);
							if (method->GetParameterCount() == 0)
							{
								ctor = method;
								break;
							}
						}
					}
					defaultConstructors.Add(typeDescriptor, ctor);
				}
				else
				{
					ctor = defaultConstructors.Values()[index];
				}
				return ctor;
			}

			IMethodInfo* GetInstanceConstructor(ITypeDescriptor* typeDescriptor)
			{
				CTOR_PARAM_PREFIX
					
				IMethodInfo* ctor = nullptr;
				vint index = instanceConstructors.Keys().IndexOf(typeDescriptor);
				if (index == -1)
				{
					if (dynamic_cast<WfClass*>(typeDescriptor))
					{
						if (auto group = typeDescriptor->GetConstructorGroup())
						{
							if (group->GetMethodCount() == 1)
							{
								auto method = group->GetMethod(0);
								vint count = method->GetParameterCount();
								for (vint i = 0; i < count; i++)
								{
									const auto& name = method->GetParameter(i)->GetName();
									if (name.Length() <= PrefixLength || name.Left(PrefixLength) != Prefix)
									{
										goto FINISHED;
									}

									if (!typeDescriptor->GetPropertyByName(CTOR_PARAM_NAME(name), false))
									{
										goto FINISHED;
									}
								}
								ctor = method;
							}
						}
					}
				FINISHED:
					instanceConstructors.Add(typeDescriptor, ctor);
				}
				else
				{
					ctor = instanceConstructors.Values()[index];
				}
				return ctor;
			}

			GlobalStringKey GetTypeName()override
			{
				return GlobalStringKey::Empty;
			}

			void ClearReflectionCache()override
			{
				propertyTypes.Clear();
				defaultConstructors.Clear();
				instanceConstructors.Clear();
			}

			//***********************************************************************************

			ITypeInfo* ProcessGenericType(ITypeInfo* propType, bool& readableList, bool& writableList, bool& collectionType)
			{
				readableList = false;
				writableList = false;
				collectionType = false;
				if (propType->GetDecorator() == ITypeInfo::SharedPtr && propType->GetElementType()->GetDecorator() == ITypeInfo::Generic)
				{
					auto genericType = propType->GetElementType();
					if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor<IValueList>())
					{
						readableList = true;
						writableList = true;
						collectionType = true;
						return genericType->GetGenericArgument(0);
					}
					else if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor<IValueObservableList>())
					{
						readableList = true;
						writableList = true;
						collectionType = true;
						return genericType->GetGenericArgument(0);
					}
					else if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor<IValueEnumerator>())
					{
						collectionType = true;
						return genericType->GetGenericArgument(0);
					}
					else if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor<IValueEnumerable>())
					{
						readableList = true;
						collectionType = true;
						return genericType->GetGenericArgument(0);
					}
					else if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor<IValueReadonlyList>())
					{
						readableList = true;
						collectionType = true;
						return genericType->GetGenericArgument(0);
					}
					else if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor<IValueReadonlyDictionary>())
					{
						collectionType = true;
						return nullptr;
					}
					else if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor<IValueDictionary>())
					{
						collectionType = true;
						return nullptr;
					}
				}
				return propType;
			}

			ITypeInfo* GetPropertyReflectionTypeInfo(const PropertyInfo& propertyInfo, GuiInstancePropertyInfo::Support& support)
			{
				support = GuiInstancePropertyInfo::NotSupport;
				IPropertyInfo* prop = propertyInfo.typeInfo.typeInfo->GetTypeDescriptor()->GetPropertyByName(propertyInfo.propertyName.ToString(), true);
				if (prop)
				{
					ITypeInfo* propType = prop->GetReturn();
					bool readableList = false;
					bool writableList = false;
					bool collectionType = false;
					auto propValueType = ProcessGenericType(propType, readableList, writableList, collectionType);

					if (prop->IsWritable())
					{
						if (collectionType)
						{
							if (readableList)
							{
								support = GuiInstancePropertyInfo::SupportArray;
								return propValueType;
							}
						}
						else
						{
							support = GuiInstancePropertyInfo::SupportAssign;
							return propValueType;
						}
					}
					else if (prop->IsReadable())
					{
						if (collectionType)
						{
							if (writableList)
							{
								support = GuiInstancePropertyInfo::SupportCollection;
								return propValueType;
							}
						}
						else
						{
							if (propType->GetDecorator() == ITypeInfo::SharedPtr || propType->GetDecorator() == ITypeInfo::RawPtr)
							{
								if (propType->GetElementType()->GetDecorator() != ITypeInfo::Generic)
								{
									support = GuiInstancePropertyInfo::SupportSet;
									return propValueType;
								}
							}
						}
					}
				}
				return nullptr;
			}

			void CollectPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, ITypeDescriptor* typeDescriptor, collections::List<GlobalStringKey>& propertyNames)
			{
				vint propertyCount = typeDescriptor->GetPropertyCount();
				for (vint i = 0; i < propertyCount; i++)
				{
					GlobalStringKey propertyName = GlobalStringKey::Get(typeDescriptor->GetProperty(i)->GetName());
					if (!propertyNames.Contains(propertyName))
					{
						auto info = GetPropertyType(precompileContext, PropertyInfo(typeInfo, propertyName));
						if (info && info->support != GuiInstancePropertyInfo::NotSupport)
						{
							propertyNames.Add(propertyName);
						}
					}
				}

				vint parentCount = typeDescriptor->GetBaseTypeDescriptorCount();
				for (vint i = 0; i < parentCount; i++)
				{
					CollectPropertyNames(precompileContext, typeInfo, typeDescriptor->GetBaseTypeDescriptor(i), propertyNames);
				}
			}

			//***********************************************************************************

			void GetRequiredPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
			{
				if (CanCreate(typeInfo))
				{
					CTOR_PARAM_PREFIX

					if (auto ctor = GetInstanceConstructor(typeInfo.typeInfo->GetTypeDescriptor()))
					{
						vint count = ctor->GetParameterCount();
						for (vint i = 0; i < count; i++)
						{
							const auto& name = ctor->GetParameter(i)->GetName();
							propertyNames.Add(GlobalStringKey::Get(CTOR_PARAM_NAME(name)));
						}
					}
				}
			}

			void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
			{
				GetRequiredPropertyNames(precompileContext, typeInfo, propertyNames);
				CollectPropertyNames(precompileContext, typeInfo, typeInfo.typeInfo->GetTypeDescriptor(), propertyNames);
			}

			PropertyType GetPropertyTypeCached(const PropertyInfo& propertyInfo)
			{
				CTOR_PARAM_PREFIX

				FieldKey key(propertyInfo.typeInfo.typeInfo->GetTypeDescriptor(), propertyInfo.propertyName);
				vint index = propertyTypes.Keys().IndexOf(key);
				if (index == -1)
				{
					GuiInstancePropertyInfo::Support support = GuiInstancePropertyInfo::NotSupport;
					if (ITypeInfo* propType = GetPropertyReflectionTypeInfo(propertyInfo, support))
					{
						auto result = Ptr(new GuiInstancePropertyInfo);
						result->support = support;
						result->acceptableTypes.Add(CopyTypeInfo(propType));

						if (auto ctor = GetInstanceConstructor(propertyInfo.typeInfo.typeInfo->GetTypeDescriptor()))
						{
							vint count = ctor->GetParameterCount();
							for (vint i = 0; i < count; i++)
							{
								const auto& name = ctor->GetParameter(i)->GetName();
								if (CTOR_PARAM_NAME(name) == propertyInfo.propertyName.ToString())
								{
									result->usage = GuiInstancePropertyInfo::ConstructorArgument;
									result->bindability = GuiInstancePropertyInfo::Bindable;
								}
							}
						}

						IPropertyInfo* prop = propertyInfo.typeInfo.typeInfo->GetTypeDescriptor()->GetPropertyByName(propertyInfo.propertyName.ToString(), true);
						PropertyType value(result, prop);
						propertyTypes.Add(key, value);
						return value;
					}
					else
					{
						PropertyType value(GuiInstancePropertyInfo::Unsupported(), nullptr);
						propertyTypes.Add(key, value);
						return value;
					}
				}
				else
				{
					return propertyTypes.Values()[index];
				}
			}

			Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
			{
				return GetPropertyTypeCached(propertyInfo).get<0>();
			}

			//***********************************************************************************

			bool CanCreate(const TypeInfo& typeInfo)override
			{
				return
					GetDefaultConstructor(typeInfo.typeInfo->GetTypeDescriptor()) != nullptr ||
					GetInstanceConstructor(typeInfo.typeInfo->GetTypeDescriptor()) != nullptr;
			}

			Ptr<workflow::WfBaseConstructorCall> CreateRootInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, ArgumentMap& arguments, GuiResourceError::List& errors)override
			{
				CTOR_PARAM_PREFIX

				if (arguments.Count() > 0)
				{
					auto call = Ptr(new WfBaseConstructorCall);

					auto baseTd = typeInfo.typeInfo->GetTypeDescriptor()->GetBaseTypeDescriptor(0);
					auto baseTypeInfo = Ptr(new TypeDescriptorTypeInfo(baseTd, TypeInfoHint::Normal));
					call->type = GetTypeFromTypeInfo(baseTypeInfo.Obj());

					auto ctor = baseTd->GetConstructorGroup()->GetMethod(0);
					vint count = ctor->GetParameterCount();
					for (vint i = 0; i < count; i++)
					{
						auto key = GlobalStringKey::Get(CTOR_PARAM_NAME(ctor->GetParameter(0)->GetName()));

						vint index = arguments.Keys().IndexOf(key);
						if (index == -1)
						{
							return nullptr;
						}
						else
						{
							call->arguments.Add(arguments.GetByIndex(index)[0].expression);
						}
					}
					return call;
				}
				return nullptr;
			}

			Ptr<workflow::WfStatement> CreateInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)override
			{
				CTOR_PARAM_PREFIX
				auto defaultCtor = GetDefaultConstructor(typeInfo.typeInfo->GetTypeDescriptor());
				auto instanceCtor = GetInstanceConstructor(typeInfo.typeInfo->GetTypeDescriptor());

				auto create = Ptr(new WfNewClassExpression);
				if (defaultCtor)
				{
					create->type = GetTypeFromTypeInfo(defaultCtor->GetReturn());
				}
				else
				{
					create->type = GetTypeFromTypeInfo(instanceCtor->GetReturn());

					vint count = instanceCtor->GetParameterCount();
					for (vint i = 0; i < count; i++)
					{
						const auto& name = instanceCtor->GetParameter(i)->GetName();
						auto key = GlobalStringKey::Get(CTOR_PARAM_NAME(name));

						vint index = arguments.Keys().IndexOf(key);
						if (index == -1)
						{
							return nullptr;
						}
						else
						{
							create->arguments.Add(arguments.GetByIndex(index)[0].expression);
						}
					}
				}

				auto refValue = Ptr(new WfReferenceExpression);
				refValue->name.value = variableName.ToString();

				auto assign = Ptr(new WfBinaryExpression);
				assign->op = WfBinaryOperator::Assign;
				assign->first = refValue;
				assign->second = create;

				auto stat = Ptr(new WfExpressionStatement);
				stat->expression = assign;
				return stat;
			}

			Ptr<workflow::WfStatement> AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
			{
				auto block = Ptr(new WfBlockStatement);

				for (auto [prop, index] : indexed(arguments.Keys()))
				{
					PropertyType propertyType = GetPropertyTypeCached(PropertyInfo(typeInfo, prop));
					if (propertyType.get<1>())
					{
						switch (propertyType.get<0>()->support)
						{
						case GuiInstancePropertyInfo::SupportCollection:
							{
								const auto& values = arguments.GetByIndex(index);
								if (values.Count() > 0)
								{
									{
										auto refValue = Ptr(new WfReferenceExpression);
										refValue->name.value = variableName.ToString();

										auto refProp = Ptr(new WfMemberExpression);
										refProp->parent = refValue;
										refProp->name.value = prop.ToString();

										auto varDesc = Ptr(new WfVariableDeclaration);
										varDesc->name.value = L"<collection>";
										varDesc->expression = refProp;

										auto stat = Ptr(new WfVariableStatement);
										stat->variable = varDesc;
										block->statements.Add(stat);
									}

									// TODO: (enumerable) foreach
									for (vint i = 0; i < values.Count(); i++)
									{
										auto refCollection = Ptr(new WfReferenceExpression);
										refCollection->name.value = L"<collection>";

										auto refAdd = Ptr(new WfMemberExpression);
										refAdd->parent = refCollection;
										refAdd->name.value = L"Add";

										auto call = Ptr(new WfCallExpression);
										call->function = refAdd;
										call->arguments.Add(values[i].expression);

										auto stat = Ptr(new WfExpressionStatement);
										stat->expression = call;
										block->statements.Add(stat);
									}
								}
							}
							break;
						case GuiInstancePropertyInfo::SupportArray:
							{
								auto refArray = Ptr(new WfConstructorExpression);
								for (auto item : arguments.GetByIndex(index))
								{
									auto argument = Ptr(new WfConstructorArgument);
									argument->key = item.expression;
									refArray->arguments.Add(argument);
								}

								auto refValue = Ptr(new WfReferenceExpression);
								refValue->name.value = variableName.ToString();

								auto refProp = Ptr(new WfMemberExpression);
								refProp->parent = refValue;
								refProp->name.value = prop.ToString();

								auto assign = Ptr(new WfBinaryExpression);
								assign->op = WfBinaryOperator::Assign;
								assign->first = refProp;
								assign->second = refArray;

								auto stat = Ptr(new WfExpressionStatement);
								stat->expression = assign;
								block->statements.Add(stat);
							}
							break;
						case GuiInstancePropertyInfo::SupportAssign:
							{
								auto& propertyValue = arguments.GetByIndex(index)[0];
								if (propertyValue.expression)
								{
									auto refValue = Ptr(new WfReferenceExpression);
									refValue->name.value = variableName.ToString();

									auto refProp = Ptr(new WfMemberExpression);
									refProp->parent = refValue;
									refProp->name.value = prop.ToString();

									auto assign = Ptr(new WfBinaryExpression);
									assign->op = WfBinaryOperator::Assign;
									assign->first = refProp;
									assign->second = propertyValue.expression;

									auto stat = Ptr(new WfExpressionStatement);
									stat->expression = assign;
									block->statements.Add(stat);
								}
							}
							break;
						default:
							errors.Add(GuiResourceError({ resolvingResult.resource }, attPosition,
								L"Precompile: Property \"" +
								prop.ToString() +
								L"\" of type \"" +
								typeInfo.typeName.ToString() +
								L"\" is not assignable."));
						}
					}
				}

				if (block->statements.Count() > 0)
				{
					return block;
				}
				return nullptr;
			}

			Ptr<workflow::WfExpression> GetParameter(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const PropertyInfo& propertyInfo, GlobalStringKey variableName, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
			{
				auto refValue = Ptr(new WfReferenceExpression);
				refValue->name.value = variableName.ToString();

				auto refProp = Ptr(new WfMemberExpression);
				refProp->parent = refValue;
				refProp->name.value = propertyInfo.propertyName.ToString();

				return refProp;
			}
		};
#undef CTOR_PARAM_NAME
#undef CTOR_PARAM_PREFIX

/***********************************************************************
GuiInstanceLoaderManager
***********************************************************************/

		IGuiInstanceLoaderManager* instanceLoaderManager = 0;

		IGuiInstanceLoaderManager* GetInstanceLoaderManager()
		{
			return instanceLoaderManager;
		}

		class GuiInstanceLoaderManager : public Object, public IGuiInstanceLoaderManager, public IGuiPlugin
		{
		protected:
			typedef Dictionary<GlobalStringKey, Ptr<IGuiInstanceBinder>>				BinderMap;
			typedef Dictionary<GlobalStringKey, Ptr<IGuiInstanceEventBinder>>			EventBinderMap;
			typedef List<Ptr<IGuiInstanceDeserializer>>									DeserializerList;

			struct VirtualTypeInfo
			{
				GlobalStringKey						typeName;
				ITypeDescriptor*					typeDescriptor = nullptr;
				GlobalStringKey						parentTypeName;				// for virtual type only
				Ptr<IGuiInstanceLoader>				loader;

				List<ITypeDescriptor*>				parentTypes;				// all direct or indirect base types that does not has a type info
				List<VirtualTypeInfo*>				parentTypeInfos;			// type infos for all registered direct or indirect base types
			};

			typedef Dictionary<GlobalStringKey, Ptr<VirtualTypeInfo>>		VirtualTypeInfoMap;

			Ptr<IGuiInstanceLoader>					rootLoader;
			BinderMap								binders;
			EventBinderMap							eventBinders;
			DeserializerList						deserializers;
			VirtualTypeInfoMap						typeInfos;

			bool IsTypeExists(GlobalStringKey name)
			{
				return GetGlobalTypeManager()->GetTypeDescriptor(name.ToString()) != 0 || typeInfos.Keys().Contains(name);
			}

			void FindParentTypeInfos(Ptr<VirtualTypeInfo> typeInfo, ITypeDescriptor* searchType)
			{
				if (searchType != typeInfo->typeDescriptor)
				{
					vint index = typeInfos.Keys().IndexOf(GlobalStringKey::Get(searchType->GetTypeName()));
					if (index == -1)
					{
						typeInfo->parentTypes.Add(searchType);
					}
					else
					{
						typeInfo->parentTypeInfos.Add(typeInfos.Values()[index].Obj());
						return;
					}
				}

				vint count = searchType->GetBaseTypeDescriptorCount();
				for (vint i = 0; i < count; i++)
				{
					ITypeDescriptor* baseType = searchType->GetBaseTypeDescriptor(i);
					FindParentTypeInfos(typeInfo, baseType);
				}
			}

			void FillParentTypeInfos(Ptr<VirtualTypeInfo> typeInfo)
			{
				if (typeInfo->parentTypeName != GlobalStringKey::Empty)
				{
					typeInfo->typeDescriptor = nullptr;
				}
				typeInfo->parentTypes.Clear();
				typeInfo->parentTypeInfos.Clear();

				ITypeDescriptor* searchType = typeInfo->typeDescriptor;
				if (!searchType)
				{
					vint index = typeInfos.Keys().IndexOf(typeInfo->parentTypeName);
					if (index == -1)
					{
						searchType = GetGlobalTypeManager()->GetTypeDescriptor(typeInfo->parentTypeName.ToString());
						typeInfo->typeDescriptor = searchType;
						typeInfo->parentTypes.Add(searchType);
					}
					else
					{
						VirtualTypeInfo* parentTypeInfo = typeInfos.Values()[index].Obj();
						typeInfo->typeDescriptor = parentTypeInfo->typeDescriptor;
						typeInfo->parentTypeInfos.Add(parentTypeInfo);
						return;
					}
				}

				if (searchType)
				{
					FindParentTypeInfos(typeInfo, searchType);
				}
			}

			IGuiInstanceLoader* GetLoaderFromType(ITypeDescriptor* typeDescriptor)
			{
				vint index = typeInfos.Keys().IndexOf(GlobalStringKey::Get(typeDescriptor->GetTypeName()));
				if (index == -1)
				{
					vint count = typeDescriptor->GetBaseTypeDescriptorCount();
					for (vint i = 0; i < count; i++)
					{
						ITypeDescriptor* baseType = typeDescriptor->GetBaseTypeDescriptor(i);
						IGuiInstanceLoader* loader = GetLoaderFromType(baseType);
						if (loader) return loader;
					}
					return 0;
				}
				else
				{
					return typeInfos.Values()[index]->loader.Obj();
				}
			}
		public:
			GuiInstanceLoaderManager()
			{
				rootLoader = Ptr(new GuiDefaultInstanceLoader);
			}

			GUI_PLUGIN_NAME(GacUI_Instance)
			{
				GUI_PLUGIN_DEPEND(GacUI_Parser);
			}

			void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerUnrelatedPlugins)
				{
					instanceLoaderManager = this;
					IGuiParserManager* manager = GetParserManager();
					manager->SetParser(L"INSTANCE-ELEMENT-NAME", Ptr(new GuiInstanceContextElementNameParser));
				}
			}

			void Unload(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerUnrelatedPlugins)
				{
					instanceLoaderManager = nullptr;
				}
			}

			bool AddInstanceBinder(Ptr<IGuiInstanceBinder> binder)override
			{
				if (binders.Keys().Contains(binder->GetBindingName())) return false;
				binders.Add(binder->GetBindingName(), binder);
				return true;
			}

			IGuiInstanceBinder* GetInstanceBinder(GlobalStringKey bindingName)override
			{
				vint index = binders.Keys().IndexOf(bindingName);
				return index == -1 ? nullptr : binders.Values()[index].Obj();
			}

			bool AddInstanceEventBinder(Ptr<IGuiInstanceEventBinder> binder)override
			{
				if (eventBinders.Keys().Contains(binder->GetBindingName())) return false;
				eventBinders.Add(binder->GetBindingName(), binder);
				return true;
			}

			IGuiInstanceEventBinder* GetInstanceEventBinder(GlobalStringKey bindingName)override
			{
				vint index = eventBinders.Keys().IndexOf(bindingName);
				return index == -1 ? nullptr : eventBinders.Values()[index].Obj();
			}

			bool AddInstanceDeserializer(Ptr<IGuiInstanceDeserializer> deserializer)override
			{
				if (deserializers.Contains(deserializer.Obj())) return false;
				deserializers.Add(deserializer);
				return true;
			}

			IGuiInstanceDeserializer* GetInstanceDeserializer(const IGuiInstanceLoader::PropertyInfo& propertyInfo, description::ITypeInfo* typeInfo)override
			{
				for (auto deserializer : deserializers)
				{
					if (deserializer->CanDeserialize(propertyInfo, typeInfo))
					{
						return deserializer.Obj();
					}
				}
				return nullptr;
			}

			bool CreateVirtualType(GlobalStringKey parentType, Ptr<IGuiInstanceLoader> loader)override
			{
				if (IsTypeExists(loader->GetTypeName()) || !IsTypeExists(parentType)) return false;

				auto typeInfo = Ptr(new VirtualTypeInfo);
				typeInfo->typeName = loader->GetTypeName();
				typeInfo->parentTypeName = parentType;
				typeInfo->loader = loader;
				typeInfos.Add(loader->GetTypeName(), typeInfo);
				FillParentTypeInfos(typeInfo);

				return true;
			}

			bool SetLoader(Ptr<IGuiInstanceLoader> loader)override
			{
				vint index = typeInfos.Keys().IndexOf(loader->GetTypeName());
				if (index != -1) return false;

				ITypeDescriptor* typeDescriptor = GetGlobalTypeManager()->GetTypeDescriptor(loader->GetTypeName().ToString());
				if (typeDescriptor == 0) return false;

				auto typeInfo = Ptr(new VirtualTypeInfo);
				typeInfo->typeName = loader->GetTypeName();
				typeInfo->typeDescriptor = typeDescriptor;
				typeInfo->loader = loader;
				typeInfos.Add(typeInfo->typeName, typeInfo);
				FillParentTypeInfos(typeInfo);

				for (auto derived : typeInfos.Values())
				{
					if (derived->parentTypes.Contains(typeInfo->typeDescriptor))
					{
						FillParentTypeInfos(derived);
					}
				}

				return true;
			}

			IGuiInstanceLoader* GetLoader(GlobalStringKey typeName)override
			{
				vint index = typeInfos.Keys().IndexOf(typeName);
				if (index != -1)
				{
					return typeInfos.Values()[index]->loader.Obj();
				}

				ITypeDescriptor* typeDescriptor = GetGlobalTypeManager()->GetTypeDescriptor(typeName.ToString());
				if (typeDescriptor)
				{
					IGuiInstanceLoader* loader = GetLoaderFromType(typeDescriptor);
					return loader ? loader : rootLoader.Obj();
				}
				return 0;
			}

			IGuiInstanceLoader* GetParentLoader(IGuiInstanceLoader* loader)override
			{
				vint index = typeInfos.Keys().IndexOf(loader->GetTypeName());
				if (index != -1)
				{
					Ptr<VirtualTypeInfo> typeInfo = typeInfos.Values()[index];
					if (typeInfo->parentTypeInfos.Count() > 0)
					{
						return typeInfo->parentTypeInfos[0]->loader.Obj();
					}
					return rootLoader.Obj();
				}
				return 0;
			}

			Ptr<description::ITypeInfo> GetTypeInfoForType(GlobalStringKey typeName)override
			{
				vint index = typeInfos.Keys().IndexOf(typeName);
				auto td = index == -1
					? GetGlobalTypeManager()->GetTypeDescriptor(typeName.ToString())
					: typeInfos.Values()[index]->typeDescriptor;
				if (!td) return nullptr;

				if (auto ctor = td->GetConstructorGroup())
				{
					return CopyTypeInfo(ctor->GetMethod(0)->GetReturn());
				}
				else if (td == description::GetTypeDescriptor<elements::IGuiGraphicsElement>())
				{
					return Ptr(new SharedPtrTypeInfo(Ptr(new TypeDescriptorTypeInfo(td, TypeInfoHint::Normal))));
				}
				else
				{
					return Ptr(new RawPtrTypeInfo(Ptr(new TypeDescriptorTypeInfo(td, TypeInfoHint::Normal))));
				}
			}

			void GetVirtualTypes(collections::List<GlobalStringKey>& typeNames)override
			{
				// TODO: (enumerable) foreach on dictionary
				for (vint i = 0; i < typeInfos.Count(); i++)
				{
					if (typeInfos.Values()[i]->parentTypeName != GlobalStringKey::Empty)
					{
						typeNames.Add(typeInfos.Keys()[i]);
					}
				}
			}

			GlobalStringKey GetParentTypeForVirtualType(GlobalStringKey virtualType)override
			{
				vint index = typeInfos.Keys().IndexOf(virtualType);
				if (index != -1)
				{
					auto typeInfo = typeInfos.Values()[index];
					return typeInfo->parentTypeName;
				}
				return GlobalStringKey::Empty;
			}

			void ClearReflectionCache()override
			{
				rootLoader->ClearReflectionCache();
				for (auto info : typeInfos.Values())
				{
					info->loader->ClearReflectionCache();
				}
			}
		};
		GUI_REGISTER_PLUGIN(GuiInstanceLoaderManager)

/***********************************************************************
Helper Functions
***********************************************************************/

		void Split(const WString& input, const WString& delimiter, collections::List<WString>& fragments)
		{
			const wchar_t* attValue = input.Buffer();
			while (*attValue)
			{
				// split the value by ';'
				const wchar_t* attSemicolon = wcsstr(attValue, delimiter.Buffer());
				WString pattern;
				if (attSemicolon)
				{
					pattern = WString::CopyFrom(attValue, vint(attSemicolon - attValue));
					attValue = attSemicolon + delimiter.Length();
				}
				else
				{
					vint len = wcslen(attValue);
					pattern = WString::CopyFrom(attValue, len);
					attValue += len;
				}

				fragments.Add(pattern);
			}
		}

		void SplitTypeName(const WString& input, collections::List<WString>& fragments)
		{
			Split(input, L"::", fragments);
		}

		void SplitBySemicolon(const WString& input, collections::List<WString>& fragments)
		{
			Split(input, L";", fragments);
		}
	}
}


/***********************************************************************
.\GUIINSTANCELOADER_PREDEFINEDINSTANCEBINDERS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace reflection::description;
		using namespace workflow;
		using namespace workflow::analyzer;
		using namespace workflow::runtime;
		using namespace instancequery;
		using namespace controls;
		using namespace stream;

/***********************************************************************
GuiResourceInstanceBinder (uri)
***********************************************************************/

		class GuiResourceInstanceBinder : public Object, public IGuiInstanceBinder
		{
		public:
			GlobalStringKey GetBindingName()override
			{
				return GlobalStringKey::_Uri;
			}

			bool ApplicableToConstructorArgument()override
			{
				return true;
			}

			bool RequirePropertyExist()override
			{
				return false;
			}

			Ptr<workflow::WfExpression> GenerateConstructorArgument(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				WString protocol, path;
				if (!IsResourceUrl(code, protocol, path))
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, position, L"Precompile: \"" + code + L"\" is not a valid resource uri."));
					return nullptr;
				}
				else if (!precompileContext.resolver->ResolveResource(protocol, path))
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, position, L"Precompile: Resource \"" + code + L"\" does not exist."));
					return nullptr;
				}
				else
				{
					return Workflow_GetUriProperty(precompileContext, resolvingResult, loader, prop, propInfo, protocol, path, position, errors);
				}
			}
			
			Ptr<workflow::WfStatement> GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				WString protocol, path;
				if (!IsResourceUrl(code, protocol, path))
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, position, L"Precompile: \"" + code + L"\" is not a valid resource uri."));
					return nullptr;
				}
				else if (!precompileContext.resolver->ResolveResource(protocol, path))
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, position, L"Precompile: Resource \"" + code + L"\" does not exist."));
					return nullptr;
				}
				else
				{
					return Workflow_InstallUriProperty(precompileContext, resolvingResult, variableName, loader, prop, propInfo, protocol, path, position, errors);
				}
			}
		};

/***********************************************************************
GuiReferenceInstanceBinder (ref)
***********************************************************************/

		class GuiReferenceInstanceBinder : public Object, public IGuiInstanceBinder
		{
		public:
			GlobalStringKey GetBindingName()override
			{
				return GlobalStringKey::_Ref;
			}

			bool ApplicableToConstructorArgument()override
			{
				return false;
			}

			bool RequirePropertyExist()override
			{
				return false;
			}

			Ptr<workflow::WfExpression> GenerateConstructorArgument(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				CHECK_FAIL(L"GuiReferenceInstanceBinder::GenerateConstructorArgument()#This binder does not support binding to constructor arguments. Please call ApplicableToConstructorArgument() to determine before calling this function.");
			}
			
			Ptr<workflow::WfStatement> GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				auto expression = Ptr(new WfReferenceExpression);
				expression->name.value = code;
				return Workflow_InstallEvalProperty(precompileContext, resolvingResult, variableName, loader, prop, propInfo, expression, position, errors);
			}
		};

/***********************************************************************
GuiEvalInstanceBinder (eval)
***********************************************************************/

		class GuiEvalInstanceBinder : public Object, public IGuiInstanceBinder
		{
		public:
			GlobalStringKey GetBindingName()override
			{
				return GlobalStringKey::_Eval;
			}

			bool ApplicableToConstructorArgument()override
			{
				return true;
			}

			bool RequirePropertyExist()override
			{
				return false;
			}

			Ptr<workflow::WfExpression> GenerateConstructorArgument(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				return Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, code, position, errors);
			}
			
			Ptr<workflow::WfStatement> GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				if(auto expression = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, code, position, errors))
				{
					return Workflow_InstallEvalProperty(precompileContext, resolvingResult, variableName, loader, prop, propInfo, expression, position, errors);
				}
				return nullptr;
			}
		};

/***********************************************************************
GuiBindInstanceBinder (bind)
***********************************************************************/

		class GuiBindInstanceBinder : public Object, public IGuiInstanceBinder
		{
		public:
			GlobalStringKey GetBindingName()override
			{
				return GlobalStringKey::_Bind;
			}

			bool ApplicableToConstructorArgument()override
			{
				return false;
			}

			bool RequirePropertyExist()override
			{
				return true;
			}

			Ptr<workflow::WfExpression> GenerateConstructorArgument(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				CHECK_FAIL(L"GuiBindInstanceBinder::GenerateConstructorArgument()#This binder does not support binding to constructor arguments. Please call ApplicableToConstructorArgument() to determine before calling this function.");
			}
			
			Ptr<workflow::WfStatement> GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				if(auto expression = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, code, position, errors))
				{
					auto inferExpr = Ptr(new WfInferExpression);
					inferExpr->expression = expression;
					inferExpr->type = GetTypeFromTypeInfo(propertyInfo->GetReturn());

					auto bindExpr = Ptr(new WfBindExpression);
					bindExpr->expression = inferExpr;

					return Workflow_InstallBindProperty(precompileContext, resolvingResult, variableName, propertyInfo, bindExpr);
				}
				return nullptr;
			}
		};

/***********************************************************************
GuiFormatInstanceBinder (format)
***********************************************************************/

		class GuiFormatInstanceBinder : public Object, public IGuiInstanceBinder
		{
		public:
			GlobalStringKey GetBindingName()override
			{
				return GlobalStringKey::_Format;
			}

			bool ApplicableToConstructorArgument()override
			{
				return false;
			}

			bool RequirePropertyExist()override
			{
				return true;
			}

			Ptr<workflow::WfExpression> GenerateConstructorArgument(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				CHECK_FAIL(L"GuiFormatInstanceBinder::GenerateConstructorArgument()#This binder does not support binding to constructor arguments. Please call ApplicableToConstructorArgument() to determine before calling this function.");
			}
			
			Ptr<workflow::WfStatement> GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				if (auto expression = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, L"bind($\"" + code + L"\")", position, errors, { 0,7 })) // bind($"
				{
					return Workflow_InstallBindProperty(precompileContext, resolvingResult, variableName, propertyInfo, expression);
				}
				return nullptr;
			}
		};

/***********************************************************************
GuiLocalizedStringInstanceBinder (str)
***********************************************************************/

		class GuiLocalizedStringInstanceBinder : public Object, public IGuiInstanceBinder
		{
		public:
			GlobalStringKey GetBindingName()override
			{
				return GlobalStringKey::_Str;
			}

			bool ApplicableToConstructorArgument()override
			{
				return false;
			}

			bool RequirePropertyExist()override
			{
				return true;
			}

			Ptr<workflow::WfExpression> GenerateConstructorArgument(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				CHECK_FAIL(L"GuiLocalizedStringInstanceBinder::GenerateConstructorArgument()#This binder does not support binding to constructor arguments. Please call ApplicableToConstructorArgument() to determine before calling this function.");
			}
			
			Ptr<workflow::WfStatement> GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				if (auto expression = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, code, position, errors, { 0,0 }))
				{
					vint errorCount = errors.Count();
					if (auto callExpr = expression.Cast<WfCallExpression>())
					{
						if (auto refExpr = callExpr->function.Cast<WfReferenceExpression>())
						{
							auto defaultLs=From(resolvingResult.context->localizeds)
								.Where([](Ptr<GuiInstanceLocalized> ls)
								{
									return ls->defaultStrings;
								})
								.First(nullptr);

							if (defaultLs)
							{
								auto thisExpr = Ptr(new WfReferenceExpression);
								thisExpr->name.value = L"<this>";
								thisExpr->codeRange = refExpr->codeRange;

								auto thisMember = Ptr(new WfMemberExpression);
								thisMember->parent = thisExpr;
								thisMember->name.value = defaultLs->name.ToString();
								thisMember->codeRange = refExpr->codeRange;

								auto refMember = Ptr(new WfMemberExpression);
								refMember->parent = thisMember;
								refMember->name.value = refExpr->name.value;
								refMember->codeRange = refExpr->codeRange;

								callExpr->function = refMember;
								goto PASSED;
							}
							else
							{
								errors.Add({ position,L"Precompiled: Omitting the name of the localized strings requires specifying a default one in <ref.LocalizedStrings> by adding a Default=\"true\" attribute." });
							}
						}
						else if (auto memberExpr = callExpr->function.Cast<WfMemberExpression>())
						{
							if (auto refStrings = memberExpr->parent.Cast<WfReferenceExpression>())
							{
								auto thisExpr = Ptr(new WfReferenceExpression);
								thisExpr->name.value = L"<this>";
								thisExpr->codeRange = refStrings->codeRange;

								auto thisMember = Ptr(new WfMemberExpression);
								thisMember->parent = thisExpr;
								thisMember->name.value = refStrings->name.value;
								thisMember->codeRange = refStrings->codeRange;

								memberExpr->parent = thisMember;
								goto PASSED;
							}
						}
						
						errors.Add({ position,L"Precompiled: The function expression in binding \"-str\" should be a \"<string-name>\" or \"<localized-strings-name>.<string-name>\"." });
					PASSED:;
					}
					else
					{
						errors.Add({ position,L"Precompiled: Expression in binding \"-str\" should be a function call expression." });
					}

					if (errorCount == errors.Count())
					{
						auto bindExpr = Ptr(new WfBindExpression);
						bindExpr->expression = expression;
						bindExpr->codeRange = expression->codeRange;

						return Workflow_InstallBindProperty(precompileContext, resolvingResult, variableName, propertyInfo, bindExpr);
					}
				}
				return nullptr;
			}
		};

/***********************************************************************
GuiEvalInstanceEventBinder (eval)
***********************************************************************/

		class GuiEvalInstanceEventBinder : public Object, public IGuiInstanceEventBinder
		{
		public:
			GlobalStringKey GetBindingName()override
			{
				return GlobalStringKey::_Eval;
			}
			
			Ptr<workflow::WfStatement> GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IEventInfo* eventInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override
			{
				bool coroutine = false;
				{
					auto reading = code.Buffer();
					while (true)
					{
						switch (*reading)
						{
						case ' ':
						case '\t':
						case '\r':
						case '\n':
							reading++;
							break;
						default:
							goto BEGIN_TESTING;
						}
					}
				BEGIN_TESTING:
					coroutine = *reading == '$';
				}

				auto parseFunction = coroutine ? &Workflow_ParseCoProviderStatement : &Workflow_ParseStatement;
				if (auto statement = parseFunction(precompileContext, { resolvingResult.resource }, code, position, errors, { 0,0 }))
				{
					return Workflow_InstallEvalEvent(precompileContext, resolvingResult, variableName, eventInfo, statement);
				}
				return nullptr;
			}
		};

/***********************************************************************
GuiPredefinedInstanceBindersPlugin
***********************************************************************/

		class GuiParser_WorkflowType : public IGuiParser<WfType>
		{
		protected:
			Ptr<workflow::Parser>						parser;

		public:
			GuiParser_WorkflowType(Ptr<workflow::Parser> _parser)
				:parser(_parser)
			{
			}

			Ptr<WfType> ParseInternal(const WString& text, List<glr::ParsingError>& errors) override
			{
				auto handler = glr::InstallDefaultErrorMessageGenerator(*parser.Obj(), errors);
				auto ast = ParseType(text, *parser.Obj());
				parser->OnError.Remove(handler);
				return ast;
			}
		};

		class GuiParser_WorkflowExpression : public IGuiParser<WfExpression>
		{
		protected:
			Ptr<workflow::Parser>						parser;

		public:
			GuiParser_WorkflowExpression(Ptr<workflow::Parser> _parser)
				:parser(_parser)
			{
			}

			Ptr<WfExpression> ParseInternal(const WString& text, List<glr::ParsingError>& errors) override
			{
				auto handler = glr::InstallDefaultErrorMessageGenerator(*parser.Obj(), errors);
				auto ast = ParseExpression(text, *parser.Obj());
				parser->OnError.Remove(handler);
				return ast;
			}
		};

		class GuiParser_WorkflowStatement : public IGuiParser<WfStatement>
		{
		protected:
			Ptr<workflow::Parser>						parser;

		public:
			GuiParser_WorkflowStatement(Ptr<workflow::Parser> _parser)
				:parser(_parser)
			{
			}

			Ptr<WfStatement> ParseInternal(const WString& text, List<glr::ParsingError>& errors) override
			{
				auto handler = glr::InstallDefaultErrorMessageGenerator(*parser.Obj(), errors);
				auto ast = ParseStatement(text, *parser.Obj());
				parser->OnError.Remove(handler);
				return ast;
			}
		};

		class GuiParser_WorkflowCoProviderStatement : public IGuiParser<WfStatement>
		{
		protected:
			Ptr<workflow::Parser>						parser;

		public:
			GuiParser_WorkflowCoProviderStatement(Ptr<workflow::Parser> _parser)
				:parser(_parser)
			{
			}

			Ptr<WfStatement> ParseInternal(const WString& text, List<glr::ParsingError>& errors) override
			{
				auto handler = glr::InstallDefaultErrorMessageGenerator(*parser.Obj(), errors);
				auto ast = ParseCoProviderStatement(text, *parser.Obj());
				parser->OnError.Remove(handler);
				return ast;
			}
		};

		class GuiParser_WorkflowDeclaration : public IGuiParser<WfDeclaration>
		{
		protected:
			Ptr<workflow::Parser>						parser;

		public:
			GuiParser_WorkflowDeclaration(Ptr<workflow::Parser> _parser)
				:parser(_parser)
			{
			}

			Ptr<WfDeclaration> ParseInternal(const WString& text, List<glr::ParsingError>& errors) override
			{
				auto handler = glr::InstallDefaultErrorMessageGenerator(*parser.Obj(), errors);
				auto ast = ParseDeclaration(text, *parser.Obj());
				parser->OnError.Remove(handler);
				return ast;
			}
		};

		class GuiParser_WorkflowModule : public IGuiParser<WfModule>
		{
		protected:
			Ptr<workflow::Parser>						parser;

		public:
			GuiParser_WorkflowModule(Ptr<workflow::Parser> _parser)
				:parser(_parser)
			{
			}

			Ptr<WfModule> ParseInternal(const WString& text, List<glr::ParsingError>& errors) override
			{
				auto handler = glr::InstallDefaultErrorMessageGenerator(*parser.Obj(), errors);
				auto ast = ParseModule(text, *parser.Obj());
				parser->OnError.Remove(handler);
				return ast;
			}
		};

		class GuiParser_InstanceQuery : public IGuiParser<GuiIqQuery>
		{
		protected:
			instancequery::Parser						parser;

		public:
			Ptr<GuiIqQuery> ParseInternal(const WString& text, List<glr::ParsingError>& errors) override
			{
				auto handler = glr::InstallDefaultErrorMessageGenerator(parser, errors);
				auto ast = parser.ParseQueryRoot(text);
				parser.OnError.Remove(handler);
				return ast;
			}
		};

		class GuiPredefinedInstanceBindersPlugin : public Object, public IGuiPlugin
		{
		public:

			GUI_PLUGIN_NAME(GacUI_Compiler_ParsersAndBinders)
			{
				GUI_PLUGIN_DEPEND(GacUI_Parser);
				GUI_PLUGIN_DEPEND(GacUI_Res_ResourceResolver);
				GUI_PLUGIN_DEPEND(GacUI_Instance);
				GUI_PLUGIN_DEPEND(GacUI_Instance_Reflection);
			}

			void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerUnrelatedPlugins)
				{
					WorkflowAstLoadTypes();
					GuiInstanceQueryAstLoadTypes();
					{
						auto workflowParser = Ptr(new workflow::Parser);

						IGuiParserManager* manager = GetParserManager();
						manager->SetParser(L"WORKFLOW-TYPE", Ptr(new GuiParser_WorkflowType(workflowParser)));
						manager->SetParser(L"WORKFLOW-EXPRESSION", Ptr(new GuiParser_WorkflowExpression(workflowParser)));
						manager->SetParser(L"WORKFLOW-STATEMENT", Ptr(new GuiParser_WorkflowStatement(workflowParser)));
						manager->SetParser(L"WORKFLOW-COPROVIDER-STATEMENT", Ptr(new GuiParser_WorkflowCoProviderStatement(workflowParser)));
						manager->SetParser(L"WORKFLOW-DECLARATION", Ptr(new GuiParser_WorkflowDeclaration(workflowParser)));
						manager->SetParser(L"WORKFLOW-MODULE", Ptr(new GuiParser_WorkflowModule(workflowParser)));
						manager->SetParser(L"INSTANCE-QUERY", Ptr(new GuiParser_InstanceQuery));
					}
					{
						IGuiInstanceLoaderManager* manager = GetInstanceLoaderManager();

						manager->AddInstanceBinder(Ptr(new GuiResourceInstanceBinder));
						manager->AddInstanceBinder(Ptr(new GuiReferenceInstanceBinder));
						manager->AddInstanceBinder(Ptr(new GuiEvalInstanceBinder));
						manager->AddInstanceBinder(Ptr(new GuiBindInstanceBinder));
						manager->AddInstanceBinder(Ptr(new GuiFormatInstanceBinder));
						manager->AddInstanceBinder(Ptr(new GuiLocalizedStringInstanceBinder));
						manager->AddInstanceEventBinder(Ptr(new GuiEvalInstanceEventBinder));
					}
				}
			}

			void Unload(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
			}
		};
		GUI_REGISTER_PLUGIN(GuiPredefinedInstanceBindersPlugin)
	}
}


/***********************************************************************
.\GUIINSTANCELOADER_PREDEFINEDINSTANCEDESERIALIZERS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace reflection::description;
		using namespace workflow;
		using namespace workflow::analyzer;
		using namespace controls;
		using namespace controls::list;
		using namespace templates;

/***********************************************************************
GuiTemplatePropertyDeserializer
***********************************************************************/

		class GuiTemplatePropertyDeserializer : public Object, public IGuiInstanceDeserializer
		{
		protected:
			Ptr<ITypeInfo>						stringType;

			bool IsTemplatePropertyType(ITypeInfo* propType)
			{
				if (propType->GetDecorator() == ITypeInfo::SharedPtr)
				{
					auto genericType = propType->GetElementType();
					if (genericType->GetDecorator() == ITypeInfo::Generic && genericType->GetGenericArgumentCount() == 2)
					{
						if (genericType->GetElementType()->GetTypeDescriptor() == description::GetTypeDescriptor<IValueFunctionProxy>())
						{
							if (genericType->GetGenericArgument(1)->GetTypeDescriptor() == description::GetTypeDescriptor<Value>())
							{
								auto returnType = genericType->GetGenericArgument(0);
								if (returnType->GetDecorator() == ITypeInfo::RawPtr)
								{
									if (returnType->GetElementType()->GetTypeDescriptor()->CanConvertTo(description::GetTypeDescriptor<GuiTemplate>()))
									{
										return true;
									}
								}
							}
						}
					}
				}
				return false;
			}

			bool IsDataVisualizerFactoryType(ITypeInfo* propType)
			{
				return propType->GetDecorator() == ITypeInfo::SharedPtr && propType->GetTypeDescriptor() == description::GetTypeDescriptor<list::IDataVisualizerFactory>();
			}

			bool IsDataEditorFactoryType(ITypeInfo* propType)
			{
				return propType->GetDecorator() == ITypeInfo::SharedPtr && propType->GetTypeDescriptor() == description::GetTypeDescriptor<list::IDataEditorFactory>();
			}

		public:
			GuiTemplatePropertyDeserializer()
			{
				stringType = TypeInfoRetriver<WString>::CreateTypeInfo();
			}

			bool CanDeserialize(const IGuiInstanceLoader::PropertyInfo& propertyInfo, description::ITypeInfo* typeInfo)override
			{
				return IsTemplatePropertyType(typeInfo) || IsDataVisualizerFactoryType(typeInfo) || IsDataEditorFactoryType(typeInfo);
			}

			description::ITypeInfo* DeserializeAs(const IGuiInstanceLoader::PropertyInfo& propertyInfo, description::ITypeInfo* typeInfo)override
			{
				return stringType.Obj();
			}

			static void GetItemTemplateType(
				types::ResolvingResult& resolvingResult,
				WString typeNamesString,
				List<ITypeDescriptor*>& tds,
				GuiResourceTextPos tagPosition,
				GuiResourceError::List& errors
				)
			{
				List<WString> typeNames;
				SplitBySemicolon(typeNamesString, typeNames);
				if (typeNames.Count() == 0)
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition,
						L"Precompile: Template list \"" +
						typeNamesString +
						L"\" cannot be empty."));
				}

				for (auto controlTemplateName : typeNames)
				{
					auto controlTemplateTd = description::GetTypeDescriptor(controlTemplateName);
					if (!controlTemplateTd)
					{
						auto index = INVLOC.FindFirst(controlTemplateName, L":", Locale::None);
						GlobalStringKey namespaceName;
						auto typeName = controlTemplateName;
						if (index.key != -1)
						{
							namespaceName = GlobalStringKey::Get(controlTemplateName.Left(index.key));
							typeName = controlTemplateName.Right(controlTemplateName.Length() - index.key - index.value);
						}

						auto source = FindInstanceLoadingSource(resolvingResult.context, namespaceName, typeName);
						if (auto typeInfo = GetInstanceLoaderManager()->GetTypeInfoForType(source.typeName))
						{
							controlTemplateTd = typeInfo->GetTypeDescriptor();
						}
					}
					if (controlTemplateTd)
					{
						tds.Add(controlTemplateTd);
					}
					else
					{
						errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition,
							L"Precompile: Type \"" +
							controlTemplateName +
							L"\" does not exist."));
						continue;
					}
				}
			}

			static Ptr<WfExpression> CreateTemplateFactory(
				types::ResolvingResult& resolvingResult,
				List<ITypeDescriptor*>& controlTemplateTds,
				ITypeInfo* returnTemplateType,
				ITypeInfo* expectedTemplateType,
				GuiResourceTextPos tagPosition,
				GuiResourceError::List& errors
				)
			{
				auto funcCreateTemplate = Ptr(new WfFunctionDeclaration);
				funcCreateTemplate->functionKind = WfFunctionKind::Normal;
				funcCreateTemplate->anonymity = WfFunctionAnonymity::Anonymous;
				funcCreateTemplate->returnType = GetTypeFromTypeInfo(returnTemplateType);

				auto argViewModel = Ptr(new WfFunctionArgument);
				argViewModel->type = GetTypeFromTypeInfo(TypeInfoRetriver<Value>::CreateTypeInfo().Obj());
				argViewModel->name.value = L"<viewModel>";
				funcCreateTemplate->arguments.Add(argViewModel);

				auto block = Ptr(new WfBlockStatement);
				funcCreateTemplate->statement = block;

				ITypeDescriptor* stopControlTemplateTd = nullptr;
				for (auto controlTemplateTd : controlTemplateTds)
				{
					if (!controlTemplateTd->CanConvertTo(expectedTemplateType->GetTypeDescriptor()))
					{
						errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition,
							L"Precompile: Type \"" +
							controlTemplateTd->GetTypeName() +
							L"\" cannot be used here because it requires \"" +
							expectedTemplateType->GetTypeDescriptor()->GetTypeName() +
							L"\" or its derived classes."));
					}

					if (stopControlTemplateTd)
					{
						errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition,
							L"Precompile: Type \"" +
							controlTemplateTd->GetTypeName() +
							L"\" will never be tried, because \"" +
							stopControlTemplateTd->GetTypeName() +
							L"\", which is listed before, has a default constructor. So whatever the view model is, it will be the last choice."));
						continue;
					}

					ITypeInfo* viewModelType = nullptr;
					{
						auto ctors = controlTemplateTd->GetConstructorGroup();
						if (!ctors || ctors->GetMethodCount() != 1)
						{
							errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition,
								L"Precompile: To use type \"" +
								controlTemplateTd->GetTypeName() +
								L"\" as a control template or item template, it should have exactly one constructor."));
							continue;
						}

						auto ctor = ctors->GetMethod(0);
						if (ctor->GetParameterCount() > 1)
						{
							errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition,
								L"Precompile: To use type \"" +
								controlTemplateTd->GetTypeName() +
								L"\" as a control template or item template, its constructor cannot have more than one parameter."));
							continue;
						}

						if (ctor->GetParameterCount() != 0)
						{
							viewModelType = ctor->GetParameter(0)->GetType();
						}
					}

					if (!viewModelType)
					{
						stopControlTemplateTd = controlTemplateTd;
					}

					auto subBlock = Ptr(new WfBlockStatement);
					block->statements.Add(subBlock);

					Ptr<ITypeInfo> controlTemplateType;
					{
						auto elementType = Ptr(new TypeDescriptorTypeInfo(controlTemplateTd, TypeInfoHint::Normal));
						auto pointerType = Ptr(new RawPtrTypeInfo(elementType));

						controlTemplateType = pointerType;
					}

					Ptr<WfBlockStatement> returnStatBlock;
					if (viewModelType)
					{
						auto refViewModel = Ptr(new WfReferenceExpression);
						refViewModel->name.value = L"<viewModel>";

						auto condition = Ptr(new WfTypeTestingExpression);
						condition->test = WfTypeTesting::IsType;
						condition->expression = refViewModel;
						condition->type = GetTypeFromTypeInfo(viewModelType);

						auto ifStat = Ptr(new WfIfStatement);
						subBlock->statements.Add(ifStat);
						ifStat->expression = condition;

						returnStatBlock = Ptr(new WfBlockStatement);
						ifStat->trueBranch = returnStatBlock;
					}
					else
					{
						returnStatBlock = subBlock;
					}

					{
						auto createControlTemplate = Ptr(new WfNewClassExpression);
						createControlTemplate->type = GetTypeFromTypeInfo(controlTemplateType.Obj());
						if (viewModelType)
						{
							auto refViewModel = Ptr(new WfReferenceExpression);
							refViewModel->name.value = L"<viewModel>";

							auto cast = Ptr(new WfTypeCastingExpression);
							cast->strategy = WfTypeCastingStrategy::Strong;
							cast->expression = refViewModel;
							cast->type = GetTypeFromTypeInfo(viewModelType);
							createControlTemplate->arguments.Add(cast);
						}

						auto returnStat = Ptr(new WfReturnStatement);
						returnStat->expression = createControlTemplate;
						returnStatBlock->statements.Add(returnStat);
					}
				}

				if (!stopControlTemplateTd)
				{
					auto value = Ptr(new WfStringExpression);
					value->value.value = L"Cannot find a matched control template to create.";

					auto raiseStat = Ptr(new WfRaiseExceptionStatement);
					raiseStat->expression = value;

					block->statements.Add(raiseStat);
				}

				auto expr = Ptr(new WfFunctionExpression);
				expr->function = funcCreateTemplate;
				return expr;
			}

			static Ptr<WfExpression> CreateDataVisualizerFactory(
				types::ResolvingResult& resolvingResult,
				List<ITypeDescriptor*>& controlTemplateTds,
				GuiResourceTextPos tagPosition,
				GuiResourceError::List& errors
			)
			{
				auto templateType = TypeInfoRetriver<GuiGridVisualizerTemplate*>::CreateTypeInfo();
				Ptr<WfExpression> previousFactory;
				for (auto [controlTemplateTd, index] : indexed(controlTemplateTds))
				{
					List<ITypeDescriptor*> tds;
					tds.Add(controlTemplateTd);
					auto refFactory = CreateTemplateFactory(resolvingResult, tds, templateType.Obj(), templateType.Obj(), tagPosition, errors);
					auto createStyle = Ptr(new WfNewClassExpression);
					createStyle->type = GetTypeFromTypeInfo(TypeInfoRetriver<Ptr<list::DataVisualizerFactory>>::CreateTypeInfo().Obj());
					createStyle->arguments.Add(refFactory);

					if (index > 0)
					{
						createStyle->arguments.Add(previousFactory);
					}
					else
					{
						auto nullExpr = Ptr(new WfLiteralExpression);
						nullExpr->value = WfLiteralValue::Null;
						createStyle->arguments.Add(nullExpr);
					}
					previousFactory = createStyle;
				}
				return previousFactory;
			}

			static Ptr<WfExpression> CreateDataEditorFactory(
				types::ResolvingResult& resolvingResult,
				List<ITypeDescriptor*>& controlTemplateTds,
				GuiResourceTextPos tagPosition,
				GuiResourceError::List& errors
			)
			{
				auto templateType = TypeInfoRetriver<GuiGridEditorTemplate*>::CreateTypeInfo();
				auto refFactory = CreateTemplateFactory(resolvingResult, controlTemplateTds, templateType.Obj(), templateType.Obj(), tagPosition, errors);
				auto createStyle = Ptr(new WfNewClassExpression);
				createStyle->type = GetTypeFromTypeInfo(TypeInfoRetriver<Ptr<list::DataEditorFactory>>::CreateTypeInfo().Obj());
				createStyle->arguments.Add(refFactory);
				return createStyle;
			}

			Ptr<workflow::WfExpression> Deserialize(
				GuiResourcePrecompileContext& precompileContext,
				types::ResolvingResult& resolvingResult,
				const IGuiInstanceLoader::PropertyInfo& propertyInfo,
				description::ITypeInfo* typeInfo,
				Ptr<workflow::WfExpression> valueExpression,
				GuiResourceTextPos tagPosition,
				GuiResourceError::List& errors
				)override
			{
				auto stringExpr = valueExpression.Cast<WfStringExpression>();

				List<ITypeDescriptor*> tds;
				GetItemTemplateType(resolvingResult, stringExpr->value.value, tds, tagPosition, errors);

				if (IsDataVisualizerFactoryType(typeInfo))
				{
					return CreateDataVisualizerFactory(resolvingResult, tds, tagPosition, errors);
				}
				else if (IsDataEditorFactoryType(typeInfo))
				{
					return CreateDataEditorFactory(resolvingResult, tds, tagPosition, errors);
				}
				else
				{
					auto returnTemplateType = typeInfo->GetElementType()->GetGenericArgument(0);
					auto expectedTemplateType = returnTemplateType;
					if (propertyInfo.propertyName == GlobalStringKey::_ControlTemplate)
					{
						auto td = propertyInfo.typeInfo.typeInfo->GetTypeDescriptor();
						if (td != nullptr && td->CanConvertTo(description::GetTypeDescriptor<GuiControl>()))
						{
							auto methodGroup = td->GetMethodGroupByName(L"GetControlTemplateObject", true);
							vint count = methodGroup->GetMethodCount();
							for (vint i = 0; i < count; i++)
							{
								auto methodInfo = methodGroup->GetMethod(i);
								if (methodInfo->GetParameterCount() == 1)
								{
									auto returnType = methodInfo->GetReturn();
									if (returnType->GetDecorator() == ITypeInfo::RawPtr)
									{
										if (returnType->GetTypeDescriptor()->CanConvertTo(description::GetTypeDescriptor<GuiControlTemplate>()))
										{
											expectedTemplateType = returnType;
										}
									}
								}
							}
						}
					}
					return CreateTemplateFactory(resolvingResult, tds, returnTemplateType, expectedTemplateType, tagPosition, errors);
				}
			}
		};

/***********************************************************************
GuiItemPropertyDeserializer
***********************************************************************/

		class GuiItemPropertyDeserializer : public Object, public IGuiInstanceDeserializer
		{
		protected:
			Ptr<ITypeInfo>						stringType;

			bool IsItemPropertyType(ITypeInfo* propType)
			{
				if (propType->GetDecorator() == ITypeInfo::SharedPtr)
				{
					auto genericType = propType->GetElementType();
					if (genericType->GetDecorator() == ITypeInfo::Generic && genericType->GetGenericArgumentCount() == 2)
					{
						if (genericType->GetElementType()->GetTypeDescriptor() == description::GetTypeDescriptor<IValueFunctionProxy>())
						{
							if (genericType->GetGenericArgument(1)->GetTypeDescriptor() == description::GetTypeDescriptor<Value>())
							{
								return true;
							}
						}
					}
				}
				return false;
			}

			bool IsWritableItemPropertyType(ITypeInfo* propType)
			{
				if (propType->GetDecorator() == ITypeInfo::SharedPtr)
				{
					auto genericType = propType->GetElementType();
					if (genericType->GetDecorator() == ITypeInfo::Generic && genericType->GetGenericArgumentCount() == 4)
					{
						if (genericType->GetElementType()->GetTypeDescriptor() == description::GetTypeDescriptor<IValueFunctionProxy>())
						{
							if (genericType->GetGenericArgument(1)->GetTypeDescriptor() == description::GetTypeDescriptor<Value>()
								&& genericType->GetGenericArgument(3)->GetTypeDescriptor() == description::GetTypeDescriptor<bool>())
							{
								if (IsSameType(genericType->GetGenericArgument(0), genericType->GetGenericArgument(2)))
								{
									return true;
								}
							}
						}
					}
				}
				return false;
			}

		public:
			GuiItemPropertyDeserializer()
			{
				stringType = TypeInfoRetriver<WString>::CreateTypeInfo();
			}

			bool CanDeserialize(const IGuiInstanceLoader::PropertyInfo& propertyInfo, description::ITypeInfo* typeInfo)override
			{
				return IsItemPropertyType(typeInfo) || IsWritableItemPropertyType(typeInfo);
			}

			description::ITypeInfo* DeserializeAs(const IGuiInstanceLoader::PropertyInfo& propertyInfo, description::ITypeInfo* typeInfo)override
			{
				return stringType.Obj();
			}

			Ptr<workflow::WfExpression> Deserialize(
				GuiResourcePrecompileContext& precompileContext,
				types::ResolvingResult& resolvingResult,
				const IGuiInstanceLoader::PropertyInfo& propertyInfo,
				description::ITypeInfo* typeInfo,
				Ptr<workflow::WfExpression> valueExpression,
				GuiResourceTextPos tagPosition,
				GuiResourceError::List& errors
				)override
			{
				auto stringExpr = valueExpression.Cast<WfStringExpression>();
				Ptr<WfExpression> propertyExpression;
				{
					propertyExpression = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, stringExpr->value.value, tagPosition, errors);
					if (!propertyExpression)
					{
						return nullptr;
					}
				};

				vint indexItemType = resolvingResult.envVars.Keys().IndexOf(GlobalStringKey::Get(L"ItemType"));
				if (indexItemType == -1)
				{
					auto error
						= L"Precompile: env.ItemType must be specified before deserializing \""
						+ stringExpr->value.value
						+ L"\" to value of type \""
						+ typeInfo->GetTypeFriendlyName()
						+ L"\".";
					errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition, error));
					return nullptr;
				}

				Ptr<WfType> itemType;
				{
					const auto& values = resolvingResult.envVars.GetByIndex(indexItemType);
					auto itemTypeValue = values[values.Count() - 1];

					itemType = Workflow_ParseType(precompileContext, { resolvingResult.resource }, itemTypeValue->value, itemTypeValue->valuePosition, errors);
					if (!itemType)
					{
						return nullptr;
					}
				};

				vint indexItemName = resolvingResult.envVars.Keys().IndexOf(GlobalStringKey::Get(L"ItemName"));
				WString itemName = WString::Unmanaged(L"item");
				if (indexItemName != -1)
				{
					const auto& values = resolvingResult.envVars.GetByIndex(indexItemName);
					itemName = values[values.Count() - 1]->value;
				}

				if (auto refExpr = propertyExpression.Cast<WfReferenceExpression>())
				{
					if (refExpr->name.value != itemName)
					{
						auto refItem = Ptr(new WfReferenceExpression);
						refItem->name.value = itemName;

						auto member = Ptr(new WfMemberExpression);
						member->parent = refItem;
						member->name.value = refExpr->name.value;

						propertyExpression = member;
					}
				}

				bool isWritableItemProperty = IsWritableItemPropertyType(typeInfo);

				auto funcDecl = Ptr(new WfFunctionDeclaration);
				ITypeInfo* acceptValueType = nullptr;
				funcDecl->functionKind = WfFunctionKind::Normal;
				funcDecl->anonymity = WfFunctionAnonymity::Anonymous;
				{
					auto genericType = typeInfo->GetElementType();
					funcDecl->returnType = GetTypeFromTypeInfo(genericType->GetGenericArgument(0));
					{
						auto argument = Ptr(new WfFunctionArgument);
						argument->name.value = L"<item>";
						argument->type = GetTypeFromTypeInfo(genericType->GetGenericArgument(1));
						funcDecl->arguments.Add(argument);
					}

					if (isWritableItemProperty)
					{
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<value>";
							argument->type = GetTypeFromTypeInfo((acceptValueType = genericType->GetGenericArgument(2)));
							funcDecl->arguments.Add(argument);
						}
						{
							auto argument = Ptr(new WfFunctionArgument);
							argument->name.value = L"<update>";
							argument->type = GetTypeFromTypeInfo(genericType->GetGenericArgument(3));
							funcDecl->arguments.Add(argument);
						}
					}
				}

				auto funcBlock = Ptr(new WfBlockStatement);
				funcDecl->statement = funcBlock;

				{
					auto refItem = Ptr(new WfReferenceExpression);
					refItem->name.value = L"<item>";

					auto refCast = Ptr(new WfTypeCastingExpression);
					refCast->strategy = WfTypeCastingStrategy::Strong;
					refCast->type = itemType;
					refCast->expression = refItem;

					auto varDecl = Ptr(new WfVariableDeclaration);
					varDecl->name.value = itemName;
					varDecl->expression = refCast;

					auto varStat = Ptr(new WfVariableStatement);
					varStat->variable = varDecl;
					funcBlock->statements.Add(varStat);
				}

				Ptr<WfReturnStatement> returnStat;
				{
					returnStat = Ptr(new WfReturnStatement);
					returnStat->expression = propertyExpression;
				}

				if (isWritableItemProperty)
				{
					auto ifStat = Ptr(new WfIfStatement);
					funcBlock->statements.Add(ifStat);
					{
						auto refUpdate = Ptr(new WfReferenceExpression);
						refUpdate->name.value = L"<update>";

						ifStat->expression = refUpdate;
					}
					{
						auto block = Ptr(new WfBlockStatement);
						ifStat->trueBranch = block;

						{
							auto refValue = Ptr(new WfReferenceExpression);
							refValue->name.value = L"<value>";

							auto assignExpr = Ptr(new WfBinaryExpression);
							assignExpr->op = WfBinaryOperator::Assign;
							assignExpr->first = CopyExpression(propertyExpression, true);

							if (acceptValueType->GetTypeDescriptor()->GetTypeDescriptorFlags() == TypeDescriptorFlags::Object)
							{
								auto castExpr = Ptr(new WfExpectedTypeCastExpression);
								castExpr->strategy = WfTypeCastingStrategy::Strong;
								castExpr->expression = refValue;
								assignExpr->second = castExpr;
							}
							else
							{
								assignExpr->second = refValue;
							}

							auto stat = Ptr(new WfExpressionStatement);
							stat->expression = assignExpr;
							block->statements.Add(stat);
						}
						{
							auto returnStat = Ptr(new WfReturnStatement);
							block->statements.Add(returnStat);

							auto returnType = typeInfo->GetElementType()->GetGenericArgument(0);
							returnStat->expression = CreateDefaultValue(returnType);
						}
					}
					{
						auto block = Ptr(new WfBlockStatement);
						ifStat->falseBranch = block;

						block->statements.Add(returnStat);
					}
				}
				else
				{
					funcBlock->statements.Add(returnStat);
				}

				auto funcExpr = Ptr(new WfFunctionExpression);
				funcExpr->function = funcDecl;
				return funcExpr;
			}
		};

/***********************************************************************
GuiDataProcessorDeserializer
***********************************************************************/

		class GuiDataProcessorDeserializer : public Object, public IGuiInstanceDeserializer
		{
		protected:
			Ptr<ITypeInfo>						stringType;

		public:
			GuiDataProcessorDeserializer()
			{
				stringType = TypeInfoRetriver<WString>::CreateTypeInfo();
			}

			bool CanDeserialize(const IGuiInstanceLoader::PropertyInfo& propertyInfo, description::ITypeInfo* typeInfo)override
			{
				return typeInfo->GetTypeDescriptor() == description::GetTypeDescriptor<IDataFilter>()
					|| typeInfo->GetTypeDescriptor() == description::GetTypeDescriptor<IDataSorter>();
			}

			description::ITypeInfo* DeserializeAs(const IGuiInstanceLoader::PropertyInfo& propertyInfo, description::ITypeInfo* typeInfo)override
			{
				return stringType.Obj();
			}

			Ptr<workflow::WfExpression> Deserialize(
				GuiResourcePrecompileContext& precompileContext,
				types::ResolvingResult& resolvingResult,
				const IGuiInstanceLoader::PropertyInfo& propertyInfo,
				description::ITypeInfo* typeInfo,
				Ptr<workflow::WfExpression> valueExpression,
				GuiResourceTextPos tagPosition,
				GuiResourceError::List& errors
				)override
			{
				auto stringExpr = valueExpression.Cast<WfStringExpression>();
				Ptr<WfExpression> propertyExpression;
				{
					propertyExpression = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, stringExpr->value.value, tagPosition, errors);
					if (!propertyExpression)
					{
						return nullptr;
					}
				};

				vint indexItemType = resolvingResult.envVars.Keys().IndexOf(GlobalStringKey::Get(L"ItemType"));
				if (indexItemType == -1)
				{
					auto error
						= L"Precompile: env.ItemType must be specified before deserializing \""
						+ stringExpr->value.value
						+ L"\" to value of type \""
						+ typeInfo->GetTypeFriendlyName()
						+ L"\".";
					errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition, error));
					return nullptr;
				}

				Ptr<WfType> itemType;
				{
					const auto& values = resolvingResult.envVars.GetByIndex(indexItemType);
					auto itemTypeValue = values[values.Count() - 1];

					itemType = Workflow_ParseType(precompileContext, { resolvingResult.resource }, itemTypeValue->value, itemTypeValue->valuePosition, errors);
					if (!itemType)
					{
						return nullptr;
					}
				};

				auto newExpr = Ptr(new WfNewInterfaceExpression);
				newExpr->type = GetTypeFromTypeInfo(typeInfo);
				{
					auto decl = Ptr(new WfFunctionDeclaration);
					newExpr->declarations.Add(decl);
					decl->functionKind = WfFunctionKind::Override;
					decl->name.value = L"SetCallback";
					decl->anonymity = WfFunctionAnonymity::Named;
					decl->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<void>::CreateTypeInfo().Obj());
					{
						auto argument = Ptr(new WfFunctionArgument);
						argument->type = GetTypeFromTypeInfo(TypeInfoRetriver<IDataProcessorCallback*>::CreateTypeInfo().Obj());
						argument->name.value = L"value";
						decl->arguments.Add(argument);
					}

					auto block = Ptr(new WfBlockStatement);
					decl->statement = block;
				}
				{
					auto decl = Ptr(new WfFunctionDeclaration);
					newExpr->declarations.Add(decl);
					decl->functionKind = WfFunctionKind::Override;
					decl->anonymity = WfFunctionAnonymity::Named;

					List<WString> argumentNames;
					if (typeInfo->GetTypeDescriptor() == description::GetTypeDescriptor<IDataFilter>())
					{
						decl->name.value = L"Filter";
						decl->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<bool>::CreateTypeInfo().Obj());
						argumentNames.Add(L"<row>");
					}
					else
					{
						decl->name.value = L"Compare";
						switch (precompileContext.targetCpuArchitecture)
						{
						case GuiResourceCpuArchitecture::x86:
							decl->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<vint32_t>::CreateTypeInfo().Obj());
							break;
						case GuiResourceCpuArchitecture::x64:
							decl->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<vint64_t>::CreateTypeInfo().Obj());
							break;
						default:
							CHECK_FAIL(L"The target CPU architecture is unspecified.");
						}
						argumentNames.Add(L"<row1>");
						argumentNames.Add(L"<row2>");
					}

					for (auto name : argumentNames)
					{
						auto argument = Ptr(new WfFunctionArgument);
						argument->type = GetTypeFromTypeInfo(TypeInfoRetriver<Value>::CreateTypeInfo().Obj());
						argument->name.value = name;
						decl->arguments.Add(argument);
					}

					auto block = Ptr(new WfBlockStatement);
					decl->statement = block;

					auto inferExpr = Ptr(new WfInferExpression);
					inferExpr->expression = propertyExpression;
					{
						auto funcType = Ptr(new WfFunctionType);
						inferExpr->type = funcType;

						funcType->result = CopyType(decl->returnType);
						// TODO: (enumerable) Linq:Select
						for (vint i = 0; i < decl->arguments.Count(); i++)
						{
							funcType->arguments.Add(CopyType(itemType));
						}
					}

					auto callExpr = Ptr(new WfCallExpression);
					callExpr->function = inferExpr;
					for (auto [name, index] : indexed(argumentNames))
					{
						auto refExpr = Ptr(new WfReferenceExpression);
						refExpr->name.value = name;

						auto castExpr = Ptr(new WfTypeCastingExpression);
						castExpr->strategy = WfTypeCastingStrategy::Strong;
						castExpr->type = (index == 0 ? itemType : CopyType(itemType));
						castExpr->expression = refExpr;

						callExpr->arguments.Add(castExpr);
					}

					auto stat = Ptr(new WfReturnStatement);
					stat->expression = callExpr;
					block->statements.Add(stat);
				}
				return newExpr;
			}
		};

/***********************************************************************
GuiPredefinedInstanceDeserializersPlugin
***********************************************************************/

		class GuiPredefinedInstanceDeserializersPlugin : public Object, public IGuiPlugin
		{
		public:

			GUI_PLUGIN_NAME(GacUI_Instance_Deserializers)
			{
				GUI_PLUGIN_DEPEND(GacUI_Instance);
			}

			void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerUnrelatedPlugins)
				{
					IGuiInstanceLoaderManager* manager = GetInstanceLoaderManager();
					manager->AddInstanceDeserializer(Ptr(new GuiTemplatePropertyDeserializer));
					manager->AddInstanceDeserializer(Ptr(new GuiItemPropertyDeserializer));
					manager->AddInstanceDeserializer(Ptr(new GuiDataProcessorDeserializer));
				}
			}

			void Unload(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
			}
		};
		GUI_REGISTER_PLUGIN(GuiPredefinedInstanceDeserializersPlugin)
	}
}


/***********************************************************************
.\GUIINSTANCELOADER_PREDEFINEDTYPERESOLVERS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace glr::xml;
		using namespace workflow;
		using namespace workflow::analyzer;
		using namespace workflow::emitter;
		using namespace workflow::runtime;
		using namespace reflection::description;
		using namespace collections;
		using namespace stream;

		using namespace controls;

		class WorkflowVirtualScriptPositionVisitor : public workflow::traverse_visitor::AstVisitor
		{
			using BaseVisitor = workflow::traverse_visitor::AstVisitor;
		public:
			GuiResourcePrecompileContext&						context;
			Ptr<types::ScriptPosition>							sp;

			WorkflowVirtualScriptPositionVisitor(GuiResourcePrecompileContext& _context)
				:context(_context)
			{
				sp = Workflow_GetScriptPosition(context);
			}

			void Visit(WfVirtualCfeExpression* node)override
			{
				BaseVisitor::Visit(node);
				vint index = sp->nodePositions.Keys().IndexOf(node);
				if (index != -1)
				{
					auto record = sp->nodePositions.Values()[index];
					Workflow_RecordScriptPosition(context, record.position, node->expandedExpression, record.availableAfter);
				}
			}

			void Visit(WfVirtualCseExpression* node)override
			{
				BaseVisitor::Visit(node);
				vint index = sp->nodePositions.Keys().IndexOf(node);
				if (index != -1)
				{
					auto record = sp->nodePositions.Values()[index];
					Workflow_RecordScriptPosition(context, record.position, node->expandedExpression, record.availableAfter);
				}
			}

			void Visit(WfVirtualCseStatement* node)override
			{
				BaseVisitor::Visit(node);
				vint index = sp->nodePositions.Keys().IndexOf(node);
				if (index != -1)
				{
					auto record = sp->nodePositions.Values()[index];
					Workflow_RecordScriptPosition(context, record.position, node->expandedStatement, record.availableAfter);
				}
			}

			void Visit(WfVirtualCfeDeclaration* node)override
			{
				BaseVisitor::Visit(node);
				vint index = sp->nodePositions.Keys().IndexOf(node);
				if (index != -1)
				{
					auto record = sp->nodePositions.Values()[index];
					for (auto decl : node->expandedDeclarations)
					{
						Workflow_RecordScriptPosition(context, record.position, decl, record.availableAfter);
					}
				}
			}

			void Visit(WfVirtualCseDeclaration* node)override
			{
				BaseVisitor::Visit(node);
				vint index = sp->nodePositions.Keys().IndexOf(node);
				if (index != -1)
				{
					auto record = sp->nodePositions.Values()[index];
					for (auto decl : node->expandedDeclarations)
					{
						Workflow_RecordScriptPosition(context, record.position, decl, record.availableAfter);
					}
				}
			}
		};

		Ptr<GuiInstanceCompiledWorkflow> Workflow_GetModule(GuiResourcePrecompileContext& context, const WString& path, Nullable<GuiInstanceCompiledWorkflow::AssemblyType> assemblyType)
		{
			auto compiled = context.targetFolder->GetValueByPath(path).Cast<GuiInstanceCompiledWorkflow>();
			if (assemblyType && !compiled)
			{
				compiled = Ptr(new GuiInstanceCompiledWorkflow);
				compiled->type = assemblyType.Value();
				context.targetFolder->CreateValueByPath(path, L"Workflow", compiled);
			}
			return compiled;
		}

		void Workflow_AddModule(GuiResourcePrecompileContext& context, const WString& path, Ptr<WfModule> module, GuiInstanceCompiledWorkflow::AssemblyType assemblyType, GuiResourceTextPos tagPosition)
		{
			auto compiled = Workflow_GetModule(context, path, assemblyType);
			CHECK_ERROR(compiled->type == assemblyType, L"Workflow_AddModule(GuiResourcePrecompiledContext&, const WString&, GuiInstanceCompiledWorkflow::AssemblyType)#Unexpected assembly type.");

			GuiInstanceCompiledWorkflow::ModuleRecord record;
			record.module = module;
			record.position = tagPosition;
			record.shared = assemblyType == GuiInstanceCompiledWorkflow::Shared;
			compiled->modules.Add(record);
		}

		void Workflow_GenerateAssembly(GuiResourcePrecompileContext& context, const WString& path, GuiResourceError::List& errors, bool keepMetadata, IWfCompilerCallback* compilerCallback)
		{
			auto compiled = Workflow_GetModule(context, path, {});
			if (!compiled)
			{
				return;
			}

			if (!compiled->assembly)
			{
				List<WString> codes;
				auto manager = Workflow_GetSharedManager(context.targetCpuArchitecture);
				manager->Clear(false, true);

				auto addCode = [&codes](TextReader& reader)
				{
					vint row = 0;
					WString code;
					while (!reader.IsEnd())
					{
						auto rowHeader = itow(++row);
						while (rowHeader.Length() < 6)
						{
							rowHeader = L" " + rowHeader;
						}
						code += rowHeader + L" : " + reader.ReadLine() + L"\r\n";
					}
					codes.Add(code);
				};

				// TODO: (enumerable) Linq:Select
				for (vint i = 0; i < compiled->modules.Count(); i++)
				{
					manager->AddModule(compiled->modules[i].module);
				}

				if (manager->errors.Count() == 0)
				{
					manager->Rebuild(true, compilerCallback);
				}

				if (manager->errors.Count() == 0)
				{
					compiled->assembly = GenerateAssembly(manager, compilerCallback);
					WfAssemblyLoadErrors loadErrors;
					if (!compiled->Initialize(true, loadErrors))
					{
						glr::ParsingError error;
						error.message = L"Internal error happened during loading an assembly that just passed type verification.";
						manager->errors.Add(error);
					}
				}
				else
				{
					// TODO: (enumerable) foreach
					for (vint i = 0; i < compiled->modules.Count(); i++)
					{
						auto module = compiled->modules[i];
						WorkflowVirtualScriptPositionVisitor visitor(context);
						visitor.InspectInto(module.module.Obj());
						Workflow_RecordScriptPosition(context, module.position, module.module);
					}

					auto sp = Workflow_GetScriptPosition(context);
					// TODO: (enumerable) foreach
					for (vint i = 0; i < manager->errors.Count(); i++)
					{
						auto error = manager->errors[i];
						errors.Add({ sp->nodePositions[error.node].computedPosition, error.message });
					}
				}

				if (keepMetadata)
				{
					compiled->metadata = Workflow_TransferSharedManager();
				}
				else
				{
					manager->Clear(false, true);
				}
			}
		}

/***********************************************************************
Shared Script Type Resolver (Script)
***********************************************************************/

#define Path_Shared				L"Workflow/Shared"
#define Path_TemporaryClass		L"Workflow/TemporaryClass"
#define Path_InstanceClass		L"Workflow/InstanceClass"

		class GuiResourceSharedScriptTypeResolver
			: public Object
			, public IGuiResourceTypeResolver
			, private IGuiResourceTypeResolver_Precompile
			, private IGuiResourceTypeResolver_IndirectLoad
		{
		public:
			WString GetType()override
			{
				return L"Script";
			}

			bool XmlSerializable()override
			{
				return true;
			}

			bool StreamSerializable()override
			{
				return false;
			}

			WString GetPreloadType()override
			{
				return L"Xml";
			}

			bool IsDelayLoad()override
			{
				return false;
			}

			PassSupport GetPrecompilePassSupport(vint passIndex)override
			{
				switch (passIndex)
				{
				case Workflow_Collect:
					return PerResource;
				case Workflow_Compile:
					return PerPass;
				default:
					return NotSupported;
				}
			}

			void PerResourcePrecompile(Ptr<GuiResourceItem> resource, GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override
			{
				switch (context.passIndex)
				{
				case Workflow_Collect:
					{
						if (auto obj = resource->GetContent().Cast<GuiInstanceSharedScript>())
						{
							if (obj->language == L"Workflow")
							{
								if (auto module = Workflow_ParseModule(context, obj->codePosition.originalLocation, obj->code, obj->codePosition, errors))
								{
									Workflow_AddModule(context, Path_Shared, module, GuiInstanceCompiledWorkflow::Shared, obj->codePosition);
								}
							}
						}
					}
					break;
				}
			}

			void PerPassPrecompile(GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override
			{
				switch (context.passIndex)
				{
				case Workflow_Compile:
					Workflow_GenerateAssembly(context, Path_Shared, errors, false, context.compilerCallback);
					if (auto compiled = Workflow_GetModule(context, Path_Shared, {}))
					{
						// TODO: (enumerable) foreach
						for (vint i = 0; i < compiled->modules.Count(); i++)
						{
							auto& module = compiled->modules[i];
							if (module.module)
							{
								module.module = CopyModule(module.module, true);
							}
						}
					}
					break;
				}
			}

			IGuiResourceTypeResolver_Precompile* Precompile()override
			{
				return this;
			}

			IGuiResourceTypeResolver_IndirectLoad* IndirectLoad()override
			{
				return this;
			}

			Ptr<DescriptableObject> Serialize(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content)override
			{
				if (auto obj = content.Cast<GuiInstanceSharedScript>())
				{
					return obj->SaveToXml();
				}
				return nullptr;
			}

			Ptr<DescriptableObject> ResolveResource(Ptr<GuiResourceItem> resource, Ptr<GuiResourcePathResolver> resolver, GuiResourceError::List& errors)override
			{
				if (auto xml = resource->GetContent().Cast<XmlDocument>())
				{
					auto schema = GuiInstanceSharedScript::LoadFromXml(resource, xml, errors);
					return schema;
				}
				return nullptr;
			}
		};

/***********************************************************************
Instance Type Resolver (Instance)
***********************************************************************/

		class GuiResourceInstanceTypeResolver
			: public Object
			, public IGuiResourceTypeResolver
			, private IGuiResourceTypeResolver_Precompile
			, private IGuiResourceTypeResolver_IndirectLoad
		{
		public:
			WString GetType()override
			{
				return L"Instance";
			}

			bool XmlSerializable()override
			{
				return true;
			}

			bool StreamSerializable()override
			{
				return false;
			}

			WString GetPreloadType()override
			{
				return L"Xml";
			}

			bool IsDelayLoad()override
			{
				return false;
			}

			PassSupport GetPrecompilePassSupport(vint passIndex)override
			{
				switch (passIndex)
				{
				case Workflow_Collect:
				case Instance_CollectInstanceTypes:
				case Instance_CollectEventHandlers:
				case Instance_GenerateInstanceClass:
					return PerResource;
				case Instance_CompileInstanceTypes:
				case Instance_CompileEventHandlers:
				case Instance_CompileInstanceClass:
					return PerPass;
				default:
					return NotSupported;
				}
			}

#define ENSURE_ASSEMBLY_EXISTS(PATH, ASSEMBLY_TYPE)\
			if (auto compiled = Workflow_GetModule(context, PATH, GuiInstanceCompiledWorkflow::ASSEMBLY_TYPE))\
			{\
				if (!compiled->assembly)\
				{\
					break;\
				}\
			}\
			else\
			{\
				break;\
			}\

#define UNLOAD_ASSEMBLY(PATH)\
			if (auto compiled = Workflow_GetModule(context, PATH, {}))\
			{\
				compiled->UnloadTypes();\
			}\

#define DELETE_ASSEMBLY(PATH)\
			if (auto compiled = Workflow_GetModule(context, PATH, {}))\
			{\
				compiled->UnloadAssembly();\
			}\

			void PerResourcePrecompile(Ptr<GuiResourceItem> resource, GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override
			{
				switch (context.passIndex)
				{
				case Workflow_Collect:
					{
						if (auto obj = resource->GetContent().Cast<GuiInstanceContext>())
						{
							auto record = context.targetFolder->GetValueByPath(L"ClassNameRecord").Cast<GuiResourceClassNameRecord>();
							if (!record)
							{
								record = Ptr(new GuiResourceClassNameRecord);
								context.targetFolder->CreateValueByPath(L"ClassNameRecord", L"ClassNameRecord", record);
							}

							if (!record->classResources.Keys().Contains(obj->className))
							{
								record->classNames.Add(obj->className);
								record->classResources.Add(obj->className, resource);
							}
						}
					}
					break;
				case Instance_CollectEventHandlers:
					ENSURE_ASSEMBLY_EXISTS(Path_TemporaryClass, TemporaryClass)
				case Instance_CollectInstanceTypes:
					{
						if (auto obj = resource->GetContent().Cast<GuiInstanceContext>())
						{
							if (obj->className == L"")
							{
								errors.Add(GuiResourceError({ resource }, obj->tagPosition,
									L"Precompile: Instance \"" +
									(obj->instance->typeNamespace == GlobalStringKey::Empty
										? obj->instance->typeName.ToString()
										: obj->instance->typeNamespace.ToString() + L":" + obj->instance->typeName.ToString()
										) +
									L"\" should have the class name specified in the ref.Class attribute."));
							}

							// TODO: (enumerable) Linq:Take
							for (auto [localized, index] :
								indexed(From(obj->localizeds).Where([](Ptr<GuiInstanceLocalized> ls) {return ls->defaultStrings; }))
								)
							{
								if (index > 0)
								{
									errors.Add(GuiResourceError({ resource }, localized->tagPosition, L"Precompile: Only one <ref.LocalizedStrings> can be the default one."));
								}
							}

							obj->ApplyStyles(resource, context.resolver, errors);

							types::ResolvingResult resolvingResult;
							resolvingResult.resource = resource;
							resolvingResult.context = obj;
							if (auto module = Workflow_GenerateInstanceClass(context, L"<instance>" + obj->className, resolvingResult, errors, context.passIndex))
							{
								Workflow_AddModule(context, Path_TemporaryClass, module, GuiInstanceCompiledWorkflow::TemporaryClass, obj->tagPosition);
							}
						}
					}
					break;
				case Instance_GenerateInstanceClass:
					{
						ENSURE_ASSEMBLY_EXISTS(Path_TemporaryClass, TemporaryClass)
						if (auto obj = resource->GetContent().Cast<GuiInstanceContext>())
						{
							vint previousErrorCount = errors.Count();

							types::ResolvingResult resolvingResult;
							resolvingResult.resource = resource;
							resolvingResult.context = obj;
							resolvingResult.rootTypeInfo = Workflow_CollectReferences(context, resolvingResult, errors);

							if (errors.Count() == previousErrorCount)
							{
								if (auto ctorModule = Workflow_PrecompileInstanceContext(context, L"<constructor>" + obj->className, resolvingResult, errors))
								{
									if (auto instanceModule = Workflow_GenerateInstanceClass(context, L"<instance>" + obj->className, resolvingResult, errors, context.passIndex))
									{
										Workflow_AddModule(context, Path_InstanceClass, ctorModule, GuiInstanceCompiledWorkflow::InstanceClass, obj->tagPosition);
										Workflow_AddModule(context, Path_InstanceClass, instanceModule, GuiInstanceCompiledWorkflow::InstanceClass, obj->tagPosition);
									}
								}
							}
						}
					}
					break;
				}
			}

			void PerPassPrecompile(GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override
			{
				WString path;
				GuiInstanceCompiledWorkflow::AssemblyType assemblyType;
				switch (context.passIndex)
				{
				case Instance_CompileInstanceTypes:
					DELETE_ASSEMBLY(Path_Shared)
					path = Path_TemporaryClass;
					assemblyType = GuiInstanceCompiledWorkflow::TemporaryClass;
					break;
				case Instance_CompileEventHandlers:
					DELETE_ASSEMBLY(Path_TemporaryClass)
					path = Path_TemporaryClass;
					assemblyType = GuiInstanceCompiledWorkflow::TemporaryClass;
					break;
				case Instance_CompileInstanceClass:
					UNLOAD_ASSEMBLY(Path_TemporaryClass)
					path = Path_InstanceClass;
					assemblyType = GuiInstanceCompiledWorkflow::InstanceClass;
					break;
				default:
					return;
				}

				auto sharedCompiled = Workflow_GetModule(context, Path_Shared, {});
				auto compiled = Workflow_GetModule(context, path, assemblyType);
				if (sharedCompiled && compiled)
				{
					CopyFrom(
						compiled->modules,
						From(sharedCompiled->modules)
							.Where([](const GuiInstanceCompiledWorkflow::ModuleRecord& module)
							{
								return module.shared;
							}),
						true
					);
				}

				switch (context.passIndex)
				{
				case Instance_CompileInstanceTypes:
					Workflow_GenerateAssembly(context, path, errors, false, context.compilerCallback);
					compiled->modules.Clear();
					break;
				case Instance_CompileEventHandlers:
					Workflow_GenerateAssembly(context, path, errors, false, context.compilerCallback);
					break;
				case Instance_CompileInstanceClass:
					Workflow_GenerateAssembly(context, path, errors, true, context.compilerCallback);
					break;
				default:;
				}
				Workflow_ClearScriptPosition(context);
				GetInstanceLoaderManager()->ClearReflectionCache();
			}

#undef DELETE_ASSEMBLY
#undef UNLOAD_ASSEMBLY
#undef ENSURE_ASSEMBLY_EXISTS

			IGuiResourceTypeResolver_Precompile* Precompile()override
			{
				return this;
			}

			IGuiResourceTypeResolver_IndirectLoad* IndirectLoad()override
			{
				return this;
			}

			Ptr<DescriptableObject> Serialize(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content)override
			{
				if (auto obj = content.Cast<GuiInstanceContext>())
				{
					return obj->SaveToXml();
				}
				return nullptr;
			}

			Ptr<DescriptableObject> ResolveResource(Ptr<GuiResourceItem> resource, Ptr<GuiResourcePathResolver> resolver, GuiResourceError::List& errors)override
			{
				if (auto xml = resource->GetContent().Cast<XmlDocument>())
				{
					Ptr<GuiInstanceContext> context = GuiInstanceContext::LoadFromXml(resource, xml, errors);
					return context;
				}
				return nullptr;
			}
		};

/***********************************************************************
Instance Style Type Resolver (InstanceStyle)
***********************************************************************/

		class GuiResourceInstanceStyleTypeResolver
			: public Object
			, public IGuiResourceTypeResolver
			, private IGuiResourceTypeResolver_IndirectLoad
		{
		public:
			WString GetType()override
			{
				return L"InstanceStyle";
			}

			bool XmlSerializable()override
			{
				return true;
			}

			bool StreamSerializable()override
			{
				return false;
			}

			WString GetPreloadType()override
			{
				return L"Xml";
			}

			bool IsDelayLoad()override
			{
				return false;
			}

			IGuiResourceTypeResolver_IndirectLoad* IndirectLoad()override
			{
				return this;
			}

			Ptr<DescriptableObject> Serialize(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content)override
			{
				if (auto obj = content.Cast<GuiInstanceStyleContext>())
				{
					return obj->SaveToXml();
				}
				return nullptr;
			}

			Ptr<DescriptableObject> ResolveResource(Ptr<GuiResourceItem> resource, Ptr<GuiResourcePathResolver> resolver, GuiResourceError::List& errors)override
			{
				if (auto xml = resource->GetContent().Cast<XmlDocument>())
				{
					auto context = GuiInstanceStyleContext::LoadFromXml(resource, xml, errors);
					return context;
				}
				return nullptr;
			}
		};

/***********************************************************************
Animation Type Resolver (Animation)
***********************************************************************/

		class GuiResourceAnimationTypeResolver
			: public Object
			, public IGuiResourceTypeResolver
			, private IGuiResourceTypeResolver_Precompile
			, private IGuiResourceTypeResolver_IndirectLoad
		{
		public:
			WString GetType()override
			{
				return L"Animation";
			}

			bool XmlSerializable()override
			{
				return true;
			}

			bool StreamSerializable()override
			{
				return false;
			}

			WString GetPreloadType()override
			{
				return L"Xml";
			}

			bool IsDelayLoad()override
			{
				return false;
			}

			PassSupport GetPrecompilePassSupport(vint passIndex)override
			{
				switch (passIndex)
				{
				case Instance_CollectInstanceTypes:
				case Instance_CollectEventHandlers:
				case Instance_GenerateInstanceClass:
					return PerResource;
				default:
					return NotSupported;
				}
			}

			void PerResourcePrecompile(Ptr<GuiResourceItem> resource, GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override
			{
				bool generateImpl = true;
				auto path = Path_InstanceClass;
				auto assemblyType = GuiInstanceCompiledWorkflow::InstanceClass;

				switch (context.passIndex)
				{
				case Instance_CollectEventHandlers:
				case Instance_CollectInstanceTypes:
					generateImpl = false;
					path = Path_TemporaryClass;
					assemblyType = GuiInstanceCompiledWorkflow::TemporaryClass;
				case Instance_GenerateInstanceClass:
					{
						if (auto obj = resource->GetContent().Cast<GuiInstanceGradientAnimation>())
						{
							if (auto module = obj->Compile(context, L"<animation>" + obj->className, generateImpl, errors))
							{
								Workflow_AddModule(context, path, module, assemblyType, obj->tagPosition);
							}
						}
					}
					break;
				}
			}

			void PerPassPrecompile(GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override
			{
				CHECK_FAIL(L"GuiResourceAnimationTypeResolver::PerPassPrecompile(GuiResourcePrecompileContext&, GuiResourceError::List&)#This function should not be called.");
			}

			IGuiResourceTypeResolver_Precompile* Precompile()override
			{
				return this;
			}

			IGuiResourceTypeResolver_IndirectLoad* IndirectLoad()override
			{
				return this;
			}

			Ptr<DescriptableObject> Serialize(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content)override
			{
				if (auto obj = content.Cast<GuiInstanceGradientAnimation>())
				{
					return obj->SaveToXml();
				}
				return nullptr;
			}

			Ptr<DescriptableObject> ResolveResource(Ptr<GuiResourceItem> resource, Ptr<GuiResourcePathResolver> resolver, GuiResourceError::List& errors)override
			{
				if (auto xml = resource->GetContent().Cast<XmlDocument>())
				{
					if (xml->rootElement->name.value == L"Gradient")
					{
						return GuiInstanceGradientAnimation::LoadFromXml(resource, xml, errors);
					}
					else
					{
						errors.Add({
							{ {resource }, xml->rootElement->codeRange.start },
							L"Precompile: Unknown animation type: \"" + xml->rootElement->name.value + L"\"."
							});
					}
				}
				return nullptr;
			}
		};

/***********************************************************************
Localized Strings Type Resolver (LocalizedStrings)
***********************************************************************/

		class GuiResourceLocalizedStringsTypeResolver
			: public Object
			, public IGuiResourceTypeResolver
			, private IGuiResourceTypeResolver_Precompile
			, private IGuiResourceTypeResolver_IndirectLoad
		{
		public:
			WString GetType()override
			{
				return L"LocalizedStrings";
			}

			bool XmlSerializable()override
			{
				return true;
			}

			bool StreamSerializable()override
			{
				return false;
			}

			WString GetPreloadType()override
			{
				return L"Xml";
			}

			bool IsDelayLoad()override
			{
				return false;
			}

			PassSupport GetPrecompilePassSupport(vint passIndex)override
			{
				switch (passIndex)
				{
				case Workflow_Collect:
				case Instance_CompileInstanceClass:
					return PerResource;
				default:
					return NotSupported;
				}
			}

			void PerResourcePrecompile(Ptr<GuiResourceItem> resource, GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override
			{
				switch (context.passIndex)
				{
				case Workflow_Collect:
					{
						if (auto obj = resource->GetContent().Cast<GuiInstanceLocalizedStrings>())
						{
							if (auto module = obj->Compile(context, L"<localized-strings>" + obj->className, errors))
							{
								Workflow_AddModule(context, Path_Shared, module, GuiInstanceCompiledWorkflow::Shared, obj->tagPosition);
							}
						}
					}
					break;
				case Instance_CompileInstanceClass:
					{
						if (auto obj = resource->GetContent().Cast<GuiInstanceLocalizedStringsInjection>())
						{
							if (auto module = obj->Compile(context, L"<localized-strings-injection>" + obj->className, errors))
							{
								Workflow_AddModule(context, Path_InstanceClass, module, GuiInstanceCompiledWorkflow::InstanceClass, obj->tagPosition);
							}
						}
					}
					break;
				}
			}

			void PerPassPrecompile(GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override
			{
				CHECK_FAIL(L"GuiResourceLocalizedStringsTypeResolver::PerPassPrecompile(GuiResourcePrecompileContext&, GuiResourceError::List&)#This function should not be called.");
			}

			IGuiResourceTypeResolver_Precompile* Precompile()override
			{
				return this;
			}

			IGuiResourceTypeResolver_IndirectLoad* IndirectLoad()override
			{
				return this;
			}

			Ptr<DescriptableObject> Serialize(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content)override
			{
				if (auto obj = content.Cast<GuiInstanceLocalizedStrings>())
				{
					return obj->SaveToXml();
				}
				if (auto obj = content.Cast<GuiInstanceLocalizedStringsInjection>())
				{
					return obj->SaveToXml();
				}
				return nullptr;
			}

			Ptr<DescriptableObject> ResolveResource(Ptr<GuiResourceItem> resource, Ptr<GuiResourcePathResolver> resolver, GuiResourceError::List& errors)override
			{
				if (auto xml = resource->GetContent().Cast<XmlDocument>())
				{
					if (xml->rootElement->name.value == L"LocalizedStrings")
					{
						return GuiInstanceLocalizedStrings::LoadFromXml(resource, xml, errors);
					}
					else if (xml->rootElement->name.value == L"LocalizedStringsInjection")
					{
						return GuiInstanceLocalizedStringsInjection::LoadFromXml(resource, xml, errors);
					}
					else
					{
						errors.Add(GuiResourceError({ { resource },xml->rootElement->codeRange.start }, L"Precompile: The root element of localized strings should be \"LocalizedStrings\" or \"LocalizedStringsInjection\"."));
					}
				}
				return nullptr;
			}
		};

#undef Path_Shared
#undef Path_TemporaryClass
#undef Path_InstanceClass

/***********************************************************************
Plugin
***********************************************************************/

		class GuiCompilerTypeResolversPlugin : public Object, public IGuiPlugin
		{
		public:

			GUI_PLUGIN_NAME(GacUI_Compiler_InstanceTypeResolvers)
			{
				GUI_PLUGIN_DEPEND(GacUI_Res_ResourceResolver);
			}

			void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerUnrelatedPlugins)
				{
					IGuiResourceResolverManager* manager = GetResourceResolverManager();
					manager->SetTypeResolver(Ptr(new GuiResourceSharedScriptTypeResolver));
					manager->SetTypeResolver(Ptr(new GuiResourceInstanceTypeResolver));
					manager->SetTypeResolver(Ptr(new GuiResourceInstanceStyleTypeResolver));
					manager->SetTypeResolver(Ptr(new GuiResourceAnimationTypeResolver));
					manager->SetTypeResolver(Ptr(new GuiResourceLocalizedStringsTypeResolver));
				}
			}

			void Unload(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
			}
		};
		GUI_REGISTER_PLUGIN(GuiCompilerTypeResolversPlugin)
	}
}


/***********************************************************************
.\GUIINSTANCELOCALIZEDSTRINGS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace glr::xml;
		using namespace workflow;
		using namespace workflow::analyzer;
		using namespace reflection::description;

/***********************************************************************
GuiInstanceLocalizedStringsBase
***********************************************************************/

		WString GuiInstanceLocalizedStringsBase::Strings::GetLocalesName()
		{
			return From(locales).Aggregate(WString(L""), [](const WString& a, const WString& b)
				{
					return a == L"" ? b : a + L";" + b;
				});
		}

/***********************************************************************
GuiInstanceLocalizedStringsBase
***********************************************************************/

		Ptr<GuiInstanceLocalizedStringsBase::Strings> GuiInstanceLocalizedStringsBase::LoadStringsFromXml(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlElement> xmlStrings, collections::SortedList<WString>& existingLocales, GuiResourceError::List& errors)
		{
			if (xmlStrings->name.value != L"Strings")
			{
				errors.Add(GuiResourceError({ { resource },xmlStrings->codeRange.start }, L"Precompile: Unknown element \"" + xmlStrings->name.value + L"\", it should be \"Strings\"."));
				return nullptr;
			}

			auto attLocales = XmlGetAttribute(xmlStrings, L"Locales");
			if (!attLocales)
			{
				errors.Add(GuiResourceError({ { resource },xmlStrings->codeRange.start }, L"Precompile: Missing attribute \"Locales\" in \"Strings\"."));
				return nullptr;
			}

			auto lss = Ptr(new GuiInstanceLocalizedStrings::Strings);
			lss->tagPosition = { { resource },xmlStrings->name.codeRange.start };
			SplitBySemicolon(attLocales->value.value, lss->locales);

			for (auto locale : lss->locales)
			{
				if (!existingLocales.Contains(locale))
				{
					existingLocales.Add(locale);
				}
				else
				{
					errors.Add(GuiResourceError({ { resource },attLocales->codeRange.start }, L"Precompile: Locale \"" + locale + L"\" already exists."));
				}
			}

			for (auto xmlString : XmlGetElements(xmlStrings))
			{
				if (xmlString->name.value != L"String")
				{
					errors.Add(GuiResourceError({ { resource },xmlString->codeRange.start }, L"Precompile: Unknown element \"" + xmlString->name.value + L"\", it should be \"String\"."));
					continue;
				}

				auto attName = XmlGetAttribute(xmlString, L"Name");
				auto attText = XmlGetAttribute(xmlString, L"Text");

				if (!attName)
				{
					errors.Add(GuiResourceError({ { resource },xmlString->codeRange.start }, L"Precompile: Missing attribute \"Name\" in \"String\"."));
				}
				if (!attText)
				{
					errors.Add(GuiResourceError({ { resource },xmlString->codeRange.start }, L"Precompile: Missing attribute \"Text\" in \"String\"."));
				}

				if (attName && attText)
				{
					if (lss->items.Keys().Contains(attName->value.value))
					{
						errors.Add(GuiResourceError({ { resource },xmlString->codeRange.start }, L"Precompile: String \"" + attName->value.value + L"\" already exists."));
					}
					else
					{
						auto item = Ptr(new GuiInstanceLocalizedStrings::StringItem);
						item->name = attName->value.value;
						item->text = attText->value.value;
						item->textPosition = { {resource},attText->value.codeRange.start };
						item->textPosition.column += 1;
						lss->items.Add(item->name, item);
					}
				}
			}

			return lss;
		}

		Ptr<glr::xml::XmlElement> GuiInstanceLocalizedStringsBase::SaveStringsToXml(Ptr<Strings> lss)
		{
			auto xmlStrings = Ptr(new XmlElement);
			xmlStrings->name.value = L"Strings";
			{
				auto att = Ptr(new XmlAttribute);
				att->name.value = L"Strings";
				att->value.value = lss->GetLocalesName();
				xmlStrings->attributes.Add(att);
			}

			for (auto lssi : lss->items.Values())
			{
				auto xmlString = Ptr(new XmlElement);
				xmlStrings->subNodes.Add(xmlString);
				{
					auto att = Ptr(new XmlAttribute);
					att->name.value = L"Name";
					att->value.value = lssi->name;
					xmlString->attributes.Add(att);
				}
				{
					auto att = Ptr(new XmlAttribute);
					att->name.value = L"Text";
					att->value.value = lssi->text;
					xmlString->attributes.Add(att);
				}
			}

			return xmlStrings;
		}

		Ptr<GuiInstanceLocalizedStrings::TextDesc> GuiInstanceLocalizedStringsBase::ParseLocalizedText(const WString& text, GuiResourceTextPos pos, GuiResourceError::List& errors)
		{
			const wchar_t* reading = text.Buffer();
			const wchar_t* textPosCounter = reading;
			glr::ParsingTextPos formatPos(0, 0);
			auto textDesc = Ptr(new TextDesc);

			auto addError = [&](const WString& message)
			{
				auto errorPos = pos;
				errorPos.row += formatPos.row;
				errorPos.column = (formatPos.row == 0 ? errorPos.column : 0) + formatPos.column;
				errors.Add({ errorPos,message });
			};

			bool addedParameter = true;
			while (*reading)
			{
				const wchar_t* begin = wcsstr(reading, L"$(");
				if (begin)
				{
					auto text = WString::CopyFrom(reading, vint(begin - reading));
					if (addedParameter)
					{
						textDesc->texts.Add(text);
					}
					else
					{
						textDesc->texts[textDesc->texts.Count() - 1] += text;
					}
				}
				else
				{
					break;
				}

				const wchar_t* end = wcsstr(begin, L")");
				if (!end)
				{
					addError(L"Precompile: Does not find matched close bracket.");
					return nullptr;
				}

				while (textPosCounter++ < begin + 2)
				{
					switch (textPosCounter[-1])
					{
					case '\n':
						formatPos.row++;
						formatPos.column = 0;
						break;
					default:
						formatPos.column++;
						break;
					}
				}

				if (end - begin == 3 && wcsncmp(begin, L"$($)", 4) == 0)
				{
					addedParameter = false;
					textDesc->texts[textDesc->texts.Count() - 1] += L"$";
				}
				else
				{
					addedParameter = true;
					const wchar_t* number = begin + 2;
					const wchar_t* numberEnd = number;
					while (L'0' <= *numberEnd && *numberEnd < L'9')
					{
						numberEnd++;
					}

					if (number == numberEnd)
					{
						addError(L"Precompile: Unexpected character, the correct format is $(index) or $(index:function).");
						return nullptr;
					}

					Ptr<ITypeInfo> type;
					WString function;
					if (*numberEnd == L':')
					{
						if (end - numberEnd > 1)
						{
							function = WString::CopyFrom(numberEnd + 1, (vint)(end - numberEnd - 1));
							if (function == L"ShortDate" || function == L"LongDate" || function == L"YearMonthDate" || function == L"ShortTime" || function == L"LongTime")
							{
								type = TypeInfoRetriver<DateTime>::CreateTypeInfo();
							}
							else if (function.Length() >= 5 && (function.Left(5) == L"Date:" || function.Left(5) == L"Time:"))
							{
								type = TypeInfoRetriver<DateTime>::CreateTypeInfo();
							}
							else if (function == L"Number" || function == L"Currency")
							{
								type = TypeInfoRetriver<WString>::CreateTypeInfo();
							}
							else
							{
								addError(L"Precompile: Unknown formatting function name \"" + function + L"\".");
								return nullptr;
							}
						}
						else
						{
							addError(L"Precompile: Unexpected character, the correct format is $(index) or $(index:function).");
							return nullptr;
						}
					}
					else if (numberEnd != end)
					{
						addError(L"Precompile: Unexpected character, the correct format is $(index) or $(index:function).");
						return nullptr;
					}

					if (!type)
					{
						type = TypeInfoRetriver<WString>::CreateTypeInfo();
					}
					textDesc->parameters.Add({ type,function });
					textDesc->positions.Add(wtoi(WString::CopyFrom(number, (vint)(numberEnd - number))));
				}
				reading = end + 1;
			}

			if (*reading || textDesc->texts.Count() == 0)
			{
				textDesc->texts.Add(reading);
			}

			for (auto [i, index] : indexed(From(textDesc->positions).OrderBySelf()))
			{
				if (i != index)
				{
					errors.Add({ pos,L"Precompile: Missing parameter \"" + itow(index) + L"\"." });
					return nullptr;
				}
			}
			return textDesc;
		}

		void GuiInstanceLocalizedStringsBase::FillStringsToTextDescMap(Ptr<Strings> lss, TextDescMap& textDescs, GuiResourceError::List& errors)
		{
			for (auto lssi : lss->items.Values())
			{
				if (auto textDesc = ParseLocalizedText(lssi->text, lssi->textPosition, errors))
				{
					textDescs.Add({ lss,lssi->name }, textDesc);
				}
			}
		}

		void GuiInstanceLocalizedStringsBase::ValidateNamesAgainstDefaultStrings(Ptr<Strings> defaultStrings, Ptr<Strings> lss, GuiResourceError::List& errors)
		{
			auto localesName = lss->GetLocalesName();

			auto missing = From(defaultStrings->items.Keys())
				.Except(lss->items.Keys())
				.Aggregate(WString(L""), [](const WString& a, const WString& b)
				{
					return a == L"" ? b : a + L", " + b;
				});
			
			auto extra = From(lss->items.Keys())
				.Except(defaultStrings->items.Keys())
				.Aggregate(WString(L""), [](const WString& a, const WString& b)
				{
					return a == L"" ? b : a + L", " + b;
				});

			if (missing != L"")
			{
				errors.Add({ lss->tagPosition,L"Precompile: Missing strings for locale \"" + localesName + L"\": " + missing + L"." });
			}

			if (extra != L"")
			{
				errors.Add({ lss->tagPosition,L"Precompile: Unnecessary strings for locale \"" + localesName + L"\": " + extra + L"." });
			}
		}

		void GuiInstanceLocalizedStringsBase::ValidateSignatureAgainstDefaultStrings(Ptr<Strings> defaultStrings, Ptr<Strings> lss, TextDescMap& textDescs, GuiResourceError::List& errors)
		{
			auto defaultLocalesName = defaultStrings->GetLocalesName();
			auto localesName = lss->GetLocalesName();

			for (auto lssi : lss->items.Values())
			{
				auto defaultDesc = textDescs[{defaultStrings, lssi->name}];
				auto textDesc = textDescs[{lss, lssi->name}];

				if (defaultDesc->parameters.Count() != textDesc->parameters.Count())
				{
					errors.Add({ lss->tagPosition,L"String \"" + lssi->name + L"\" in locales \"" + defaultLocalesName + L"\" and \"" + localesName + L"\" have different numbers of parameters." });
				}
				else
				{
					// TODO: (enumerable) foreach:indexed
					for (vint i = 0; i < textDesc->parameters.Count(); i++)
					{
						auto defaultParameter = defaultDesc->parameters[defaultDesc->positions[i]];
						auto parameter = textDesc->parameters[textDesc->positions[i]];

						if (defaultParameter.key->GetTypeDescriptor()->GetTypeName() != parameter.key->GetTypeDescriptor()->GetTypeName())
						{
							errors.Add({ lss->tagPosition,L"Parameter \"" + itow(i) + L"\" in String \"" + lssi->name + L"\" in locales \"" + defaultLocalesName + L"\" and \"" + localesName + L"\" are in different types \"" + defaultParameter.key->GetTypeFriendlyName() + L"\" and \"" + parameter.key->GetTypeFriendlyName() + L"\"." });
						}
					}
				}
			}
		}

		void GuiInstanceLocalizedStringsBase::ValidateAgainstDefaultStrings(Ptr<Strings> defaultStrings, collections::List<Ptr<Strings>>& nonDefaultStrings, TextDescMap& textDescs, GuiResourceError::List& errors)
		{
			vint errorCount = errors.Count();
			for (auto lss : nonDefaultStrings)
			{
				ValidateNamesAgainstDefaultStrings(defaultStrings, lss, errors);
			}
			if (errors.Count() != errorCount)
			{
				return;
			}

			for (auto lss : nonDefaultStrings)
			{
				FillStringsToTextDescMap(lss, textDescs, errors);
			}
			if (errors.Count() != errorCount)
			{
				return;
			}

			for (auto lss : nonDefaultStrings)
			{
				ValidateSignatureAgainstDefaultStrings(defaultStrings, lss, textDescs, errors);
			}
			if (errors.Count() != errorCount)
			{
				return;
			}
		}

		WString GuiInstanceLocalizedStringsBase::GetInterfaceTypeName(const WString& className, bool hasNamespace)
		{
			auto pair = INVLOC.FindLast(className, L"::", Locale::None);
			if (pair.key == -1)
			{
				return L"I" + className + L"Strings";
			}
			else
			{
				auto ns = className.Left(pair.key + 2);
				auto name = className.Right(className.Length() - ns.Length());
				return(hasNamespace ? ns : L"") + L"I" + name + L"Strings";
			}
		}

		WString GuiInstanceLocalizedStringsBase::GenerateStringsCppName(Ptr<Strings> lss)
		{
			auto encoded = From(lss->locales)
				.Aggregate(
					WString::Empty,
					[](auto&& a, auto&& b)
					{
						return a + WString::Unmanaged(L"_") + b;
					});
			return WString::Unmanaged(L"<ls") + encoded + WString::Unmanaged(L">BuildStrings");
		}

		Ptr<workflow::WfFunctionDeclaration> GuiInstanceLocalizedStringsBase::GenerateTextDescFunctionHeader(Ptr<TextDesc> textDesc, const WString& functionName, workflow::WfFunctionKind functionKind)
		{
			auto func = Ptr(new WfFunctionDeclaration);
			func->functionKind = functionKind;
			func->anonymity = WfFunctionAnonymity::Named;
			func->name.value = functionName;
			func->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<WString>::CreateTypeInfo().Obj());
			// TODO: (enumerable) foreach
			for (vint i = 0; i < textDesc->positions.Count(); i++)
			{
				auto type = textDesc->parameters[textDesc->positions[i]];

				auto argument = Ptr(new WfFunctionArgument);
				argument->name.value = L"<ls>" + itow(i);
				argument->type = GetTypeFromTypeInfo(type.key.Obj());
				func->arguments.Add(argument);
			}

			return func;
		}

		Ptr<workflow::WfExpression> GuiInstanceLocalizedStringsBase::GenerateTextDescArgumentFormatting(Ptr<description::ITypeInfo> type, const WString& function, vint argumentIndex)
		{
			WString argumentName = L"<ls>" + itow(argumentIndex);
			if (function == L"ShortDate" || function == L"LongDate" || function == L"YearMonthDate" || function == L"ShortTime" || function == L"LongTime")
			{
				auto refLoc = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<Localization>());

				auto refFormats = Ptr(new WfChildExpression);
				refFormats->parent = refLoc;
				refFormats->name.value = L"Get" + function + L"Formats";

				auto refLocale = Ptr(new WfReferenceExpression);
				refLocale->name.value = L"<ls>locale";

				auto callFormats = Ptr(new WfCallExpression);
				callFormats->function = refFormats;
				callFormats->arguments.Add(refLocale);

				auto refFirst = Ptr(new WfChildExpression);
				refFirst->parent = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<helper_types::LocalizedStrings>());
				refFirst->name.value = L"FirstOrEmpty";

				auto callFirst = Ptr(new WfCallExpression);
				{
					callFirst->function = refFirst;
					callFirst->arguments.Add(callFormats);
				}

				auto refLocale2 = Ptr(new WfReferenceExpression);
				refLocale2->name.value = L"<ls>locale";

				auto refParameter = Ptr(new WfReferenceExpression);
				refParameter->name.value = argumentName;

				auto refLoc2 = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<Localization>());

				auto refFD = Ptr(new WfChildExpression);
				refFD->parent = refLoc2;
				refFD->name.value = L"Format" + function.Right(4);

				auto callFD = Ptr(new WfCallExpression);
				callFD->function = refFD;
				callFD->arguments.Add(refLocale2);
				callFD->arguments.Add(callFirst);
				callFD->arguments.Add(refParameter);

				return callFD;
			}
			else if (function.Length() >= 5 && (function.Left(5) == L"Date:" || function.Left(5) == L"Time:"))
			{
				auto refLocale = Ptr(new WfReferenceExpression);
				refLocale->name.value = L"<ls>locale";

				auto refFormat = Ptr(new WfStringExpression);
				refFormat->value.value = function.Right(function.Length() - 5);

				auto refParameter = Ptr(new WfReferenceExpression);
				refParameter->name.value = argumentName;

				auto refLoc2 = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<Localization>());

				auto refFD = Ptr(new WfChildExpression);
				refFD->parent = refLoc2;
				refFD->name.value = L"Format" + function.Left(4);

				auto callFD = Ptr(new WfCallExpression);
				callFD->function = refFD;
				callFD->arguments.Add(refLocale);
				callFD->arguments.Add(refFormat);
				callFD->arguments.Add(refParameter);

				return callFD;
			}
			else if (function == L"Number" || function == L"Currency")
			{
				auto refLocale = Ptr(new WfReferenceExpression);
				refLocale->name.value = L"<ls>locale";

				auto refParameter = Ptr(new WfReferenceExpression);
				refParameter->name.value = argumentName;

				auto refLoc2 = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<Localization>());

				auto refFD = Ptr(new WfChildExpression);
				refFD->parent = refLoc2;
				refFD->name.value = L"Format" + function;

				auto callFD = Ptr(new WfCallExpression);
				callFD->function = refFD;
				callFD->arguments.Add(refLocale);
				callFD->arguments.Add(refParameter);

				return callFD;
			}
			else
			{
				auto refParameter = Ptr(new WfReferenceExpression);
				refParameter->name.value = argumentName;

				return refParameter;
			}
		}

		Ptr<workflow::WfBlockStatement> GuiInstanceLocalizedStringsBase::GenerateTextDescFunctionBody(Ptr<TextDesc> textDesc)
		{
			auto appendExpr = [](Ptr<WfExpression> resultExpr, Ptr<WfExpression> strExpr) -> Ptr<WfExpression>
			{
				if (resultExpr)
				{
					auto binaryExpr = Ptr(new WfBinaryExpression);
					binaryExpr->op = WfBinaryOperator::FlagAnd;
					binaryExpr->first = resultExpr;
					binaryExpr->second = strExpr;

					return binaryExpr;
				}
				else
				{
					return strExpr;
				}
			};

			auto block = Ptr(new WfBlockStatement);

			// TODO: (enumerable) foreach:indexed
			for (vint i = 0; i < textDesc->parameters.Count(); i++)
			{
				auto varDesc = Ptr(new WfVariableDeclaration);
				varDesc->name.value = L"<ls>_" + itow(i);

				auto varStat = Ptr(new WfVariableStatement);
				varStat->variable = varDesc;
				block->statements.Add(varStat);

				auto type = textDesc->parameters[i].key;
				auto function = textDesc->parameters[i].value;
				auto index = textDesc->positions[i];
				varDesc->expression = GenerateTextDescArgumentFormatting(type, function, index);
			}

			{
				Ptr<WfExpression> resultExpr;
				// TODO: (enumerable) foreach:indexed
				for (vint i = 0; i < textDesc->texts.Count(); i++)
				{
					if (textDesc->texts[i] != L"")
					{
						auto strExpr = Ptr(new WfStringExpression);
						strExpr->value.value = textDesc->texts[i];
						resultExpr = appendExpr(resultExpr, strExpr);
					}

					if (i < textDesc->parameters.Count())
					{
						auto refExpr = Ptr(new WfReferenceExpression);
						refExpr->name.value = L"<ls>_" + itow(i);
						resultExpr = appendExpr(resultExpr, refExpr);
					}
				}

				if (!resultExpr)
				{
					resultExpr = Ptr(new WfStringExpression);
				}

				auto returnStat = Ptr(new WfReturnStatement);
				returnStat->expression = resultExpr;
				block->statements.Add(returnStat);
			}

			return block;
		}

		template<typename TResult, typename TTopQualified, typename TChild>
		Ptr<TResult> GenerateFullNameAst(const WString& fullName)
		{
			Ptr<TResult> refClass;
			{
				List<WString> fragments;
				SplitTypeName(fullName, fragments);
				for (auto fragment : fragments)
				{
					if (refClass)
					{
						auto refType = Ptr(new TChild);
						refType->parent = refClass;
						refType->name.value = fragment;
						refClass = refType;
					}
					else
					{
						auto refType = Ptr(new TTopQualified);
						refType->name.value = fragment;
						refClass = refType;
					}
				}
			}
			return refClass;
		}

		Ptr<workflow::WfExpression> GuiInstanceLocalizedStringsBase::GenerateStringsConstructor(const WString& interfaceFullName, TextDescMap& textDescs, Ptr<Strings> lss)
		{
			auto lsExpr = Ptr(new WfNewInterfaceExpression);
			{
				auto refPointer = Ptr(new WfSharedPointerType);
				refPointer->element = GenerateFullNameAst<WfType, WfTopQualifiedType, WfChildType>(interfaceFullName);

				lsExpr->type = refPointer;
			}

			for (auto lssi : lss->items.Values())
			{
				auto textDesc = textDescs[{lss, lssi->name}];
				auto func = GenerateTextDescFunctionHeader(textDesc, lssi->name, WfFunctionKind::Override);
				func->statement = GenerateTextDescFunctionBody(textDesc);
				lsExpr->declarations.Add(func);
			}

			return lsExpr;
		}

		Ptr<workflow::WfFunctionDeclaration> GuiInstanceLocalizedStringsBase::GenerateBuildStringsFunction(const WString& interfaceFullName, TextDescMap& textDescs, Ptr<Strings> lss)
		{
			auto func = Ptr(new WfFunctionDeclaration);
			func->functionKind = WfFunctionKind::Static;
			func->anonymity = WfFunctionAnonymity::Named;
			func->name.value = GenerateStringsCppName(lss);
			{
				auto refPointer = Ptr(new WfSharedPointerType);
				refPointer->element = GenerateFullNameAst<WfType, WfTopQualifiedType, WfChildType>(interfaceFullName);

				func->returnType = refPointer;
			}
			{
				auto argument = Ptr(new WfFunctionArgument);
				argument->name.value = L"<ls>locale";
				argument->type = GetTypeFromTypeInfo(TypeInfoRetriver<Locale>::CreateTypeInfo().Obj());
				func->arguments.Add(argument);
			}

			auto block = Ptr(new WfBlockStatement);
			func->statement = block;
			
			auto returnStat = Ptr(new WfReturnStatement);
			returnStat->expression = GenerateStringsConstructor(interfaceFullName, textDescs, lss);
			block->statements.Add(returnStat);

			return func;
		}

		Ptr<workflow::WfBlockStatement> GuiInstanceLocalizedStringsBase::GenerateStaticInit(const WString& stringsClassWithoutNs, const WString& installClassFullName, collections::List<Ptr<Strings>>& strings)
		{
			auto block = Ptr(new WfBlockStatement);

			for (auto ls : strings)
			{
				auto cppName = GenerateStringsCppName(ls);
				for (auto locale : ls->locales)
				{
					Ptr<WfExpression> exprStrings, exprInstall;
					{
						auto refClass = Ptr(new WfReferenceExpression);
						refClass->name.value = stringsClassWithoutNs;

						auto refStrings = Ptr(new WfChildExpression);
						refStrings->parent = refClass;
						refStrings->name.value = GenerateStringsCppName(ls);

						auto strExpr = Ptr(new WfStringExpression);
						strExpr->value.value = locale;

						auto castExpr = Ptr(new WfExpectedTypeCastExpression);
						castExpr->strategy = WfTypeCastingStrategy::Strong;
						castExpr->expression = strExpr;

						auto callStringsExpr = Ptr(new WfCallExpression);
						callStringsExpr->function = refStrings;
						callStringsExpr->arguments.Add(castExpr);

						exprStrings = callStringsExpr;
					}
					{
						auto strExpr = Ptr(new WfStringExpression);
						strExpr->value.value = locale;

						auto castExpr = Ptr(new WfExpectedTypeCastExpression);
						castExpr->strategy = WfTypeCastingStrategy::Strong;
						castExpr->expression = strExpr;

						auto refInstall = Ptr(new WfChildExpression);
						refInstall->parent = GenerateFullNameAst<WfExpression, WfTopQualifiedExpression, WfChildExpression>(installClassFullName);
						refInstall->name.value = L"Install";

						auto callInstallExpr = Ptr(new WfCallExpression);
						callInstallExpr->function = refInstall;
						callInstallExpr->arguments.Add(castExpr);
						callInstallExpr->arguments.Add(exprStrings);

						exprInstall = callInstallExpr;
					}
					auto exprStat = Ptr(new WfExpressionStatement);
					exprStat->expression = exprInstall;
					block->statements.Add(exprStat);
				}
			}

			return block;
		}

/***********************************************************************
GuiInstanceLocalizedStrings
***********************************************************************/

		Ptr<GuiInstanceLocalizedStrings> GuiInstanceLocalizedStrings::LoadFromXml(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlDocument> xml, GuiResourceError::List& errors)
		{
			auto ls = Ptr(new GuiInstanceLocalizedStrings);

			if (xml->rootElement->name.value!=L"LocalizedStrings")
			{
				errors.Add(GuiResourceError({ { resource },xml->rootElement->codeRange.start }, L"Precompile: The root element of localized strings should be \"LocalizedStrings\"."));
				return nullptr;
			}
			ls->tagPosition = { {resource},xml->rootElement->name.codeRange.start };

			auto attClassName = XmlGetAttribute(xml->rootElement, L"ref.Class");
			if (!attClassName)
			{
				errors.Add(GuiResourceError({ { resource },xml->rootElement->codeRange.start }, L"Precompile: Missing attribute \"ref.Class\" in \"LocalizedStrings\"."));
			}
			else
			{
				ls->className = attClassName->value.value;
			}

			auto attDefaultLocale = XmlGetAttribute(xml->rootElement, L"DefaultLocale");
			if (!attDefaultLocale)
			{
				errors.Add(GuiResourceError({ { resource },xml->rootElement->codeRange.start }, L"Precompile: Missing attribute \"DefaultLocale\" in \"LocalizedStrings\"."));
			}
			else
			{
				ls->defaultLocale = attDefaultLocale->value.value;
			}

			if (!attClassName || !attDefaultLocale)
			{
				return nullptr;
			}

			SortedList<WString> existingLocales;
			for (auto xmlStrings : XmlGetElements(xml->rootElement))
			{
				if (auto lss = LoadStringsFromXml(resource, xmlStrings, existingLocales, errors))
				{
					ls->strings.Add(lss);
					if (lss->locales.Contains(ls->defaultLocale))
					{
						ls->defaultStrings = lss;
					}
				}
			}

			if (!ls->defaultStrings)
			{
				errors.Add(GuiResourceError({ { resource },xml->rootElement->codeRange.start }, L"Precompile: Strings for the default locale \"" + ls->defaultLocale + L"\" is not defined."));
			}

			return ls;
		}

		Ptr<glr::xml::XmlElement> GuiInstanceLocalizedStrings::SaveToXml()
		{
			auto xml = Ptr(new XmlElement);
			xml->name.value = L"LocalizedStrings";
			{
				auto att = Ptr(new XmlAttribute);
				att->name.value = L"ref.Class";
				att->value.value = className;
				xml->attributes.Add(att);
			}
			{
				auto att = Ptr(new XmlAttribute);
				att->name.value = L"DefaultLocale";
				att->value.value = defaultLocale;
				xml->attributes.Add(att);
			}

			for (auto lss : strings)
			{
				xml->subNodes.Add(SaveStringsToXml(lss));
			}

			return xml;
		}

		Ptr<workflow::WfFunctionDeclaration> GuiInstanceLocalizedStrings::GenerateInstallFunction(const WString& cacheName)
		{
			auto func = Ptr(new WfFunctionDeclaration);
			func->functionKind = WfFunctionKind::Static;
			func->anonymity = WfFunctionAnonymity::Named;
			func->name.value = L"Install";
			{
				auto refVoid = Ptr(new WfPredefinedType);
				refVoid->name = WfPredefinedTypeName::Void;
				func->returnType = refVoid;
			}
			{
				auto argument = Ptr(new WfFunctionArgument);
				argument->name.value = L"<ls>locale";
				argument->type = GetTypeFromTypeInfo(TypeInfoRetriver<Locale>::CreateTypeInfo().Obj());
				func->arguments.Add(argument);
			}
			{
				auto refType = Ptr(new WfReferenceType);
				refType->name.value = GetInterfaceTypeName(className, false);

				auto refPointer = Ptr(new WfSharedPointerType);
				refPointer->element = refType;

				auto argument = Ptr(new WfFunctionArgument);
				argument->name.value = L"<ls>impl";
				argument->type = refPointer;
				func->arguments.Add(argument);
			}

			auto block = Ptr(new WfBlockStatement);
			func->statement = block;

			{
				auto ifStat = Ptr(new WfIfStatement);
				{
					auto refCache = Ptr(new WfReferenceExpression);
					refCache->name.value = cacheName;

					auto refKeys = Ptr(new WfMemberExpression);
					refKeys->parent = refCache;
					refKeys->name.value = L"Keys";

					auto refContains = Ptr(new WfMemberExpression);
					refContains->parent = refKeys;
					refContains->name.value = L"Contains";

					auto refLocale = Ptr(new WfReferenceExpression);
					refLocale->name.value = L"<ls>locale";

					auto callExpr = Ptr(new WfCallExpression);
					callExpr->function = refContains;
					callExpr->arguments.Add(refLocale);

					ifStat->expression = callExpr;
				}

				auto trueBlock = Ptr(new WfBlockStatement);
				ifStat->trueBranch = trueBlock;

				auto raiseStat = Ptr(new WfRaiseExceptionStatement);
				trueBlock->statements.Add(raiseStat);
				{
					auto errorHead = Ptr(new WfStringExpression);
					errorHead->value.value = L"Localized strings \"" + className + L"\" has already registered for locale \"";

					auto refLocale = Ptr(new WfReferenceExpression);
					refLocale->name.value = L"<ls>locale";

					auto errorTail = Ptr(new WfStringExpression);
					errorTail->value.value = L"\".";

					auto concat0 = Ptr(new WfBinaryExpression);
					concat0->op = WfBinaryOperator::FlagAnd;
					concat0->first = errorHead;
					concat0->second = refLocale;

					auto concat1 = Ptr(new WfBinaryExpression);
					concat1->op = WfBinaryOperator::FlagAnd;
					concat1->first = concat0;
					concat1->second = errorTail;

					raiseStat->expression = concat1;
				}

				block->statements.Add(ifStat);
			}
			{
				auto callExpr = Ptr(new WfCallExpression);
				{
					auto refCache = Ptr(new WfReferenceExpression);
					refCache->name.value = cacheName;

					auto refSet = Ptr(new WfMemberExpression);
					refSet->parent = refCache;
					refSet->name.value = L"Set";

					callExpr->function = refSet;
				}
				{
					auto refLocale = Ptr(new WfReferenceExpression);
					refLocale->name.value = L"<ls>locale";

					callExpr->arguments.Add(refLocale);
				}
				{
					auto refImpl = Ptr(new WfReferenceExpression);
					refImpl->name.value = L"<ls>impl";

					callExpr->arguments.Add(refImpl);
				}

				auto exprStat = Ptr(new WfExpressionStatement);
				exprStat->expression = callExpr;
				block->statements.Add(exprStat);
			}

			return func;
		}

		Ptr<workflow::WfFunctionDeclaration> GuiInstanceLocalizedStrings::GenerateGetFunction(const WString& cacheName)
		{
			auto func = Ptr(new WfFunctionDeclaration);
			func->functionKind = WfFunctionKind::Static;
			func->anonymity = WfFunctionAnonymity::Named;
			func->name.value = L"Get";
			{
				auto refType = Ptr(new WfReferenceType);
				refType->name.value = GetInterfaceTypeName(className, false);

				auto refPointer = Ptr(new WfSharedPointerType);
				refPointer->element = refType;

				func->returnType = refPointer;
			}
			{
				auto argument = Ptr(new WfFunctionArgument);
				argument->name.value = L"<ls>locale";
				argument->type = GetTypeFromTypeInfo(TypeInfoRetriver<Locale>::CreateTypeInfo().Obj());
				func->arguments.Add(argument);
			}

			auto block = Ptr(new WfBlockStatement);
			func->statement = block;

			{
				auto ifStat = Ptr(new WfIfStatement);
				{
					auto refCache = Ptr(new WfReferenceExpression);
					refCache->name.value = cacheName;

					auto refKeys = Ptr(new WfMemberExpression);
					refKeys->parent = refCache;
					refKeys->name.value = L"Keys";

					auto refContains = Ptr(new WfMemberExpression);
					refContains->parent = refKeys;
					refContains->name.value = L"Contains";

					auto refLocale = Ptr(new WfReferenceExpression);
					refLocale->name.value = L"<ls>locale";

					auto callExpr = Ptr(new WfCallExpression);
					callExpr->function = refContains;
					callExpr->arguments.Add(refLocale);

					ifStat->expression = callExpr;
				}

				auto trueBlock = Ptr(new WfBlockStatement);
				ifStat->trueBranch = trueBlock;

				{
					auto refCache = Ptr(new WfReferenceExpression);
					refCache->name.value = cacheName;

					auto refLocale = Ptr(new WfReferenceExpression);
					refLocale->name.value = L"<ls>locale";

					auto refGet = Ptr(new WfBinaryExpression);
					refGet->op = WfBinaryOperator::Index;
					refGet->first = refCache;
					refGet->second = refLocale;

					auto returnStat = Ptr(new WfReturnStatement);
					returnStat->expression = refGet;
					trueBlock->statements.Add(returnStat);
				}

				block->statements.Add(ifStat);
			}
			{
				auto refCache = Ptr(new WfReferenceExpression);
				refCache->name.value = cacheName;

				auto strExpr = Ptr(new WfStringExpression);
				strExpr->value.value = defaultLocale;

				auto castExpr = Ptr(new WfExpectedTypeCastExpression);
				castExpr->strategy = WfTypeCastingStrategy::Strong;
				castExpr->expression = strExpr;

				auto refGet = Ptr(new WfBinaryExpression);
				refGet->op = WfBinaryOperator::Index;
				refGet->first = refCache;
				refGet->second = castExpr;

				auto returnStat = Ptr(new WfReturnStatement);
				returnStat->expression = refGet;
				block->statements.Add(returnStat);
			}

			return func;
		}

		Ptr<workflow::WfModule> GuiInstanceLocalizedStrings::Compile(GuiResourcePrecompileContext& precompileContext, const WString& moduleName, GuiResourceError::List& errors)
		{
			vint errorCount = errors.Count();
			TextDescMap textDescs;
			{
				List<Ptr<Strings>> nonDefaultStrings;
				CopyFrom(
					nonDefaultStrings,
					From(strings).Where([this](auto&& lss) { return lss != defaultStrings; })
					);

				FillStringsToTextDescMap(defaultStrings, textDescs, errors);
				ValidateAgainstDefaultStrings(defaultStrings, nonDefaultStrings, textDescs, errors);
			}
			if (errors.Count() != errorCount)
			{
				return nullptr;
			}

			WString cacheName;

			auto module = Ptr(new WfModule);
			module->moduleType = WfModuleType::Module;
			module->name.value = moduleName;

			// interface
			{
				auto lsInterface = Workflow_InstallClass(GetInterfaceTypeName(className, true), module);
				lsInterface->kind = WfClassKind::Interface;
				lsInterface->constructorType = WfConstructorType::SharedPtr;

				for (auto functionName : defaultStrings->items.Keys())
				{
					auto func = GenerateTextDescFunctionHeader(textDescs[{defaultStrings, functionName}], functionName, WfFunctionKind::Normal);
					lsInterface->declarations.Add(func);
				}
			}

			// cache
			{
				auto refType = Ptr(new WfReferenceType);
				refType->name.value = GetInterfaceTypeName(className, false);
				
				auto ptrType = Ptr(new WfSharedPointerType);
				ptrType->element = refType;
				
				auto mapType = Ptr(new WfMapType);
				mapType->writability = WfMapWritability::Writable;
				mapType->key = GetTypeFromTypeInfo(TypeInfoRetriver<Locale>::CreateTypeInfo().Obj());
				mapType->value = ptrType;
				
				auto lsCache = Ptr(new WfVariableDeclaration);
				lsCache->type = mapType;
				lsCache->expression = Ptr(new WfConstructorExpression);
				
				cacheName = L"<ls>" + Workflow_InstallWithClass(className, module, lsCache);
				lsCache->name.value = cacheName;
			}

			// class
			{
				auto lsClass = Workflow_InstallClass(className, module);
				for (auto ls : strings)
				{
					lsClass->declarations.Add(GenerateBuildStringsFunction(GetInterfaceTypeName(className, true), textDescs, ls));
				}
				lsClass->declarations.Add(GenerateInstallFunction(cacheName));
				lsClass->declarations.Add(GenerateGetFunction(cacheName));
			}

			// init
			{
				auto lsInit = Ptr(new WfStaticInitDeclaration);
				auto classNameWithoutNs = Workflow_InstallWithClass(className, module, lsInit);
				lsInit->statement = GenerateStaticInit(classNameWithoutNs, className, strings);
			}

			glr::ParsingTextPos pos(tagPosition.row, tagPosition.column);
			SetCodeRange(module, { pos,pos });
			return module;
		}

/***********************************************************************
GuiInstanceLocalizedStringsInjection
***********************************************************************/

		Ptr<GuiInstanceLocalizedStringsInjection> GuiInstanceLocalizedStringsInjection::LoadFromXml(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlDocument> xml, GuiResourceError::List& errors)
		{
			auto ls = Ptr(new GuiInstanceLocalizedStringsInjection);

			if (xml->rootElement->name.value!=L"LocalizedStringsInjection")
			{
				errors.Add(GuiResourceError({ { resource },xml->rootElement->codeRange.start }, L"Precompile: The root element of localized strings should be \"LocalizedStringsInjection\"."));
				return nullptr;
			}
			ls->tagPosition = { {resource},xml->rootElement->name.codeRange.start };

			auto attClassName = XmlGetAttribute(xml->rootElement, L"ref.Class");
			if (!attClassName)
			{
				errors.Add(GuiResourceError({ { resource },xml->rootElement->codeRange.start }, L"Precompile: Missing attribute \"ref.Class\" in \"LocalizedStringsInjection\"."));
			}
			else
			{
				ls->className = attClassName->value.value;
			}

			auto attInjectIntoClassName = XmlGetAttribute(xml->rootElement, L"ref.InjectInto");
			if (!attInjectIntoClassName)
			{
				errors.Add(GuiResourceError({ { resource },xml->rootElement->codeRange.start }, L"Precompile: Missing attribute \"ref.InjectInto\" in \"LocalizedStringsInjection\"."));
			}
			else
			{
				ls->injectIntoClassName = attInjectIntoClassName->value.value;
			}

			if (!attClassName || !attInjectIntoClassName)
			{
				return nullptr;
			}

			SortedList<WString> existingLocales;
			for (auto xmlStrings : XmlGetElements(xml->rootElement))
			{
				if (auto lss = LoadStringsFromXml(resource, xmlStrings, existingLocales, errors))
				{
					ls->strings.Add(lss);
				}
			}

			return ls;
		}

		Ptr<glr::xml::XmlElement> GuiInstanceLocalizedStringsInjection::SaveToXml()
		{
			auto xml = Ptr(new XmlElement);
			xml->name.value = L"LocalizedStringsInjection";
			{
				auto att = Ptr(new XmlAttribute);
				att->name.value = L"ref.Class";
				att->value.value = className;
				xml->attributes.Add(att);
			}
			{
				auto att = Ptr(new XmlAttribute);
				att->name.value = L"ref.InjectInto";
				att->value.value = injectIntoClassName;
				xml->attributes.Add(att);
			}

			for (auto lss : strings)
			{
				xml->subNodes.Add(SaveStringsToXml(lss));
			}

			return xml;
		}

		void GuiInstanceLocalizedStringsInjection::DecompileDefaultStrings(description::ITypeDescriptor* td, Ptr<Strings> defaultStrings, TextDescMap& textDescs, GuiResourceError::List& errors)
		{
			auto tdString = description::GetTypeDescriptor<WString>();
			auto tdDateTime = description::GetTypeDescriptor<DateTime>();

			for (vint i = 0; i < td->GetMethodGroupCount(); i++)
			{
				auto tdMethodGroup = td->GetMethodGroup(i);
				if (tdMethodGroup->GetMethodCount() == 1)
				{
					vint errorCount = errors.Count();
					auto tdMethod = tdMethodGroup->GetMethod(0);
					auto returnType = tdMethod->GetReturn();

					if (returnType->GetDecorator() != ITypeInfo::TypeDescriptor || returnType->GetTypeDescriptor() != tdString)
					{
						errors.Add(GuiResourceError(tagPosition, L"Precompile: function \"" + tdMethod->GetName() + L"\" in interface \"" + td->GetTypeName() + L"\" does not return string."));
					}

					for (vint j = 0; j < tdMethod->GetParameterCount(); j++)
					{
						auto tdParameter = tdMethod->GetParameter(j);
						if (tdParameter->GetType()->GetDecorator() != ITypeInfo::TypeDescriptor || (
							tdParameter->GetType()->GetTypeDescriptor() != tdString &&
							tdParameter->GetType()->GetTypeDescriptor() != tdDateTime))
						{
							errors.Add(GuiResourceError(tagPosition, L"Precompile: argument \"" + tdParameter->GetName() + L"\" in function \"" + tdMethod->GetName() + L"\" in interface \"" + td->GetTypeName() + L"\" is not string or DateTime."));
						}
					}

					if (errors.Count() == errorCount)
					{
						defaultStrings->items.Add(
							tdMethod->GetName(),
							Ptr(new StringItem{ .name = tdMethod->GetName() })
							);

						auto textDesc = Ptr(new TextDesc);
						textDescs.Add({ defaultStrings,tdMethod->GetName() }, textDesc);

						CopyFrom(
							textDesc->parameters,
							Range<vint>(0, tdMethod->GetParameterCount())
								.Select([tdMethod](vint j) -> ParameterPair
								{
									return { CopyTypeInfo(tdMethod->GetParameter(j)->GetType()),WString::Empty };
								})
							);

						CopyFrom(
							textDesc->positions,
							Range<vint>(0, tdMethod->GetParameterCount())
							);
					}
				}
				else
				{
					errors.Add(GuiResourceError(tagPosition, L"Precompile: interface \"" + td->GetTypeName() + L"\" has more than one function named \"" + tdMethodGroup->GetName() + L"\"."));
				}
			}
		}

		Ptr<workflow::WfModule> GuiInstanceLocalizedStringsInjection::Compile(GuiResourcePrecompileContext& precompileContext, const WString& moduleName, GuiResourceError::List& errors)
		{
			auto tdInjectInto = description::GetTypeDescriptor(injectIntoClassName);
			if (!tdInjectInto)
			{
				errors.Add(GuiResourceError(tagPosition, L"Precompile: attribute \"ref.InjectInto\" specifies an unexisting type \"" + injectIntoClassName + L"\"."));
				return nullptr;
			}

			IMethodGroupInfo* tdGetMethodGroup = nullptr;
			IMethodInfo* tdGetMethod = nullptr;
			IParameterInfo* tdGetMethodParameter = nullptr;
			ITypeDescriptor* tdStringsInterface = nullptr;

			tdGetMethodGroup = tdInjectInto->GetMethodGroupByName(L"Get", false);
			if (!tdGetMethodGroup) goto INCORRECT_STRINGS_TYPE;
			if (tdGetMethodGroup->GetMethodCount() != 1) goto INCORRECT_STRINGS_TYPE;

			tdGetMethod = tdGetMethodGroup->GetMethod(0);
			if (!tdGetMethod->IsStatic()) goto INCORRECT_STRINGS_TYPE;
			if (tdGetMethod->GetParameterCount() != 1) goto INCORRECT_STRINGS_TYPE;
			if (tdGetMethod->GetReturn()->GetDecorator() != ITypeInfo::SharedPtr) goto INCORRECT_STRINGS_TYPE;

			tdGetMethodParameter = tdGetMethod->GetParameter(0);
			if (tdGetMethodParameter->GetType()->GetDecorator() != ITypeInfo::TypeDescriptor) goto INCORRECT_STRINGS_TYPE;
			if (tdGetMethodParameter->GetType()->GetTypeDescriptor() != description::GetTypeDescriptor<Locale>()) goto INCORRECT_STRINGS_TYPE;

			tdStringsInterface = tdGetMethod->GetReturn()->GetTypeDescriptor();
			if (tdStringsInterface->GetTypeName() != GetInterfaceTypeName(injectIntoClassName, true)) goto INCORRECT_STRINGS_TYPE;

			{
				vint errorCount = errors.Count();
				auto defaultStrings = Ptr(new Strings);
				TextDescMap textDescs;

				DecompileDefaultStrings(tdStringsInterface, defaultStrings, textDescs, errors);
				if (errors.Count() != errorCount)
				{
					return nullptr;
				}

				ValidateAgainstDefaultStrings(defaultStrings, strings, textDescs, errors);
				if (errors.Count() != errorCount)
				{
					return nullptr;
				}

				auto module = Ptr(new WfModule);
				module->moduleType = WfModuleType::Module;
				module->name.value = moduleName;

				// class
				{
					auto lsClass = Workflow_InstallClass(className, module);
					for (auto ls : strings)
					{
						lsClass->declarations.Add(GenerateBuildStringsFunction(GetInterfaceTypeName(injectIntoClassName, true), textDescs, ls));
					}
				}

				// init
				{
					auto lsInit = Ptr(new WfStaticInitDeclaration);
					auto classNameWithoutNs = Workflow_InstallWithClass(className, module, lsInit);
					lsInit->statement = GenerateStaticInit(classNameWithoutNs, injectIntoClassName, strings);
				}

				glr::ParsingTextPos pos(tagPosition.row, tagPosition.column);
				SetCodeRange(module, { pos,pos });
				return module;
			}
		INCORRECT_STRINGS_TYPE:
			errors.Add(GuiResourceError(tagPosition, L"Precompile: attribute \"ref.InjectInto\" specifies a type \"" + injectIntoClassName + L"\" that is not generated by <LocalizedStrings/>."));
			return nullptr;
		}
	}
}

/***********************************************************************
.\GUIINSTANCEREPRESENTATION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace glr::xml;
		using namespace templates;
		using namespace stream;

/***********************************************************************
GuiValueRepr
***********************************************************************/

		void GuiValueRepr::CloneBody(Ptr<GuiValueRepr> repr)
		{
			repr->fromStyle = fromStyle;
			repr->tagPosition = tagPosition;
		}

/***********************************************************************
GuiTextRepr
***********************************************************************/

		Ptr<GuiValueRepr> GuiTextRepr::Clone()
		{
			auto repr = Ptr(new GuiTextRepr);
			GuiValueRepr::CloneBody(repr);
			repr->text = text;
			return repr;
		}

		void GuiTextRepr::FillXml(Ptr<glr::xml::XmlElement> xml)
		{
			if (!fromStyle)
			{
				auto xmlText = Ptr(new XmlText);
				xmlText->content.value = text;
				xml->subNodes.Add(xmlText);
			}
		}

/***********************************************************************
GuiAttSetterRepr
***********************************************************************/

		void GuiAttSetterRepr::CloneBody(Ptr<GuiAttSetterRepr> repr)
		{
			GuiValueRepr::CloneBody(repr);

			// TODO: (enumerable) foreach on dictionary
			for (auto [name, index] : indexed(setters.Keys()))
			{
				auto src = setters.Values()[index];
				auto dst = Ptr(new SetterValue);

				dst->binding = src->binding;
				dst->attPosition = src->attPosition;
				for (auto value : src->values)
				{
					dst->values.Add(value->Clone());
				}

				repr->setters.Add(name, dst);
			}

			// TODO: (enumerable) foreach on dictionary
			for (auto [name, index] : indexed(eventHandlers.Keys()))
			{
				auto src = eventHandlers.Values()[index];
				auto dst = Ptr(new EventValue);

				dst->binding = src->binding;
				dst->value = src->value;
				dst->fromStyle = src->fromStyle;
				dst->attPosition = src->attPosition;
				dst->valuePosition = src->valuePosition;

				repr->eventHandlers.Add(name, dst);
			}

			// TODO: (enumerable) foreach on dictionary
			for (auto [name, index] : indexed(environmentVariables.Keys()))
			{
				auto src = environmentVariables.Values()[index];
				auto dst = Ptr(new EnvVarValue);

				dst->value = src->value;
				dst->fromStyle = src->fromStyle;
				dst->attPosition = src->attPosition;
				dst->valuePosition = src->valuePosition;

				repr->environmentVariables.Add(name, dst);
			}

			repr->instanceName = instanceName;
		}

		Ptr<GuiValueRepr> GuiAttSetterRepr::Clone()
		{
			auto repr = Ptr(new GuiAttSetterRepr);
			GuiAttSetterRepr::CloneBody(repr);
			repr->fromStyle = fromStyle;
			return repr;
		}

		void GuiAttSetterRepr::FillXml(Ptr<glr::xml::XmlElement> xml)
		{
			if (!fromStyle)
			{
				if (instanceName != GlobalStringKey::Empty)
				{
					auto attName = Ptr(new XmlAttribute);
					attName->name.value = L"ref.Name";
					attName->value.value = instanceName.ToString();
					xml->attributes.Add(attName);
				}

				// TODO: (enumerable) foreach on dictionary
				for (vint i = 0; i < setters.Count(); i++)
				{
					auto key = setters.Keys()[i];
					auto value = setters.Values()[i];
					if (key == GlobalStringKey::Empty)
					{
						for (auto repr : value->values)
						{
							repr->FillXml(xml);
						}
					}
					else if (From(value->values).Any([](Ptr<GuiValueRepr> value) {return !value->fromStyle; }))
					{
						bool containsElement = From(value->values)
							.Any([](Ptr<GuiValueRepr> value)
							{
								return !value->fromStyle && !value.Cast<GuiTextRepr>();
							});

						if (containsElement)
						{
							auto xmlProp = Ptr(new XmlElement);
							xmlProp->name.value = L"att." + key.ToString();
							if (value->binding != GlobalStringKey::Empty)
							{
								xmlProp->name.value += L"-" + value->binding.ToString();
							}

							for (auto repr : value->values)
							{
								if (!repr.Cast<GuiTextRepr>())
								{
									repr->FillXml(xmlProp);
								}
							}
							xml->subNodes.Add(xmlProp);
						}
						else
						{
							for (auto repr : value->values)
							{
								if (auto textRepr = repr.Cast<GuiTextRepr>())
								{
									if (!textRepr->fromStyle)
									{
										auto att = Ptr(new XmlAttribute);
										att->name.value = key.ToString();
										if (value->binding != GlobalStringKey::Empty)
										{
											att->name.value += L"-" + value->binding.ToString();
										}
										att->value.value = textRepr->text;
										xml->attributes.Add(att);
										break;
									}
								}
							}
						}
					}
				}

				// TODO: (enumerable) foreach on dictionary
				for (vint i = 0; i < eventHandlers.Count(); i++)
				{
					auto key = eventHandlers.Keys()[i];
					auto value = eventHandlers.Values()[i];
					if (!value->fromStyle)
					{
						auto xmlEvent = Ptr(new XmlElement);
						xmlEvent->name.value = L"ev." + key.ToString();
						if (value->binding != GlobalStringKey::Empty)
						{
							xmlEvent->name.value += L"-" + value->binding.ToString();
						}
						xml->subNodes.Add(xmlEvent);

						auto xmlText = Ptr(new XmlCData);
						xmlText->content.value = value->value;
						xmlEvent->subNodes.Add(xmlText);
					}
				}

				// TODO: (enumerable) foreach on dictionary
				for (vint i = 0; i < environmentVariables.Count(); i++)
				{
					auto key = environmentVariables.Keys()[i];
					auto value = environmentVariables.Values()[i];
					if (!value->fromStyle)
					{
						auto xmlEnvVar = Ptr(new XmlElement);
						xmlEnvVar->name.value = L"env." + key.ToString();
						xml->subNodes.Add(xmlEnvVar);

						auto xmlText = Ptr(new XmlText);
						xmlText->content.value = value->value;
						xmlEnvVar->subNodes.Add(xmlText);
					}
				}
			}
		}

/***********************************************************************
GuiConstructorRepr
***********************************************************************/

		Ptr<GuiValueRepr> GuiConstructorRepr::Clone()
		{
			auto repr = Ptr(new GuiConstructorRepr);
			GuiAttSetterRepr::CloneBody(repr);
			repr->fromStyle = fromStyle;
			repr->typeNamespace = typeNamespace;
			repr->typeName = typeName;
			repr->styleName = styleName;
			return repr;
		}

		void GuiConstructorRepr::FillXml(Ptr<glr::xml::XmlElement> xml)
		{
			if (!fromStyle)
			{
				auto xmlCtor = Ptr(new XmlElement);
				if (typeNamespace == GlobalStringKey::Empty)
				{
					xmlCtor->name.value = typeName.ToString();
				}
				else
				{
					xmlCtor->name.value = typeNamespace.ToString() + L":" + typeName.ToString();
				}

				if (styleName)
				{
					auto attStyle = Ptr(new XmlAttribute);
					attStyle->name.value = L"ref.Style";
					attStyle->value.value = styleName.Value();
					xml->attributes.Add(attStyle);
				}

				GuiAttSetterRepr::FillXml(xmlCtor);
				xml->subNodes.Add(xmlCtor);
			}
		}

/***********************************************************************
GuiInstanceContext
***********************************************************************/

		void GuiInstanceContext::CollectDefaultAttributes(Ptr<GuiResourceItem> resource, GuiAttSetterRepr::ValueList& values, Ptr<glr::xml::XmlElement> xml, GuiResourceError::List& errors)
		{
			if (auto parser = GetParserManager()->GetParser<ElementName>(L"INSTANCE-ELEMENT-NAME"))
			{
				// test if there is only one text value in the xml
				if (xml->subNodes.Count() == 1)
				{
					if (Ptr<XmlText> text = xml->subNodes[0].Cast<XmlText>())
					{
						auto value = Ptr(new GuiTextRepr);
						value->text = text->content.value;
						value->tagPosition = { {resource},text->content.codeRange.start };
						values.Add(value);
					}
					else if (Ptr<XmlCData> text = xml->subNodes[0].Cast<XmlCData>())
					{
						auto value = Ptr(new GuiTextRepr);
						value->text = text->content.value;
						value->tagPosition = { {resource},text->content.codeRange.start };
						value->tagPosition.column += 9; // <![CDATA[
						values.Add(value);
					}
				}

				// collect default attributes
				for (auto element : XmlGetElements(xml))
				{
					if(auto name = parser->Parse({ resource }, element->name.value, element->codeRange.start, errors))
					{
						if (name->IsCtorName())
						{
							// collect constructor values in the default attribute setter
							auto ctor = LoadCtor(resource, element, errors);
							if (ctor)
							{
								values.Add(ctor);
							}
						}
						else if (!name->IsPropertyElementName() && !name->IsEventElementName())
						{
							errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"Unknown element name: \"" + element->name.value + L"\"."));
						}
					}
				}
			}
		}

		void GuiInstanceContext::CollectAttributes(Ptr<GuiResourceItem> resource, GuiAttSetterRepr::SetteValuerMap& setters, Ptr<glr::xml::XmlElement> xml, GuiResourceError::List& errors)
		{
			if (auto parser = GetParserManager()->GetParser<ElementName>(L"INSTANCE-ELEMENT-NAME"))
			{
				auto defaultValue = Ptr(new GuiAttSetterRepr::SetterValue);

				// collect default attributes
				CollectDefaultAttributes(resource, defaultValue->values, xml, errors);
				if (defaultValue->values.Count() > 0)
				{
					setters.Add(GlobalStringKey::Empty, defaultValue);
				}

				// collect values
				for (auto element : XmlGetElements(xml))
				{
					if(auto name = parser->Parse({ resource }, element->name.value, element->name.codeRange.start, errors))
					{
						if (name->IsPropertyElementName())
						{
							// collect a value as a new attribute setter
							if (setters.Keys().Contains(GlobalStringKey::Get(name->name)))
							{
								errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"Duplicated property \"" + name->name + L"\"."));
							}
							else
							{
								auto sv = Ptr(new GuiAttSetterRepr::SetterValue);
								sv->binding = GlobalStringKey::Get(name->binding);
								sv->attPosition = { {resource},element->codeRange.start };

								if (name->binding == L"set")
								{
									// if the binding is "set", it means that this element is a complete setter element
									auto setter = Ptr(new GuiAttSetterRepr);
									FillAttSetter(resource, setter, element, errors);
									sv->values.Add(setter);
								}
								else
								{
									// if the binding is not "set", then this is a single-value attribute or a colection attribute
									// fill all data into this attribute
									CollectDefaultAttributes(resource, sv->values, element, errors);
								}

								if (sv->values.Count() > 0)
								{
									setters.Add(GlobalStringKey::Get(name->name), sv);
								}
							}
						}
					}
				}
			}
		}

		void GuiInstanceContext::CollectEvents(Ptr<GuiResourceItem> resource, GuiAttSetterRepr::EventHandlerMap& eventHandlers, Ptr<glr::xml::XmlElement> xml, GuiResourceError::List& errors)
		{
			if (auto parser = GetParserManager()->GetParser<ElementName>(L"INSTANCE-ELEMENT-NAME"))
			{
				// collect values
				for (auto element : XmlGetElements(xml))
				{
					if(auto name = parser->Parse({ resource }, element->name.value, element->name.codeRange.start, errors))
					{
						if (name->IsEventElementName())
						{
							// collect a value as an event setter
							if (eventHandlers.Keys().Contains(GlobalStringKey::Get(name->name)))
							{
								errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"Duplicated event \"" + name->name + L"\"."));
							}
							else
							{
								// test if there is only one text value in the xml
								if (element->subNodes.Count() == 1)
								{
									if (Ptr<XmlText> text = element->subNodes[0].Cast<XmlText>())
									{
										auto value = Ptr(new GuiAttSetterRepr::EventValue);
										value->binding = GlobalStringKey::Get(name->binding);
										value->value = text->content.value;
										value->attPosition = { {resource},element->codeRange.start };
										value->valuePosition = { {resource},text->content.codeRange.start };
										eventHandlers.Add(GlobalStringKey::Get(name->name), value);
										if (text->content.codeRange.start.row != text->content.codeRange.end.row)
										{
											errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"Multiple lines script should be contained in a CDATA section."));
										}
										goto EVENT_SUCCESS;
									}
									else if (Ptr<XmlCData> text = element->subNodes[0].Cast<XmlCData>())
									{
										auto value = Ptr(new GuiAttSetterRepr::EventValue);
										value->binding = GlobalStringKey::Get(name->binding);
										value->value = text->content.value;
										value->attPosition = { {resource},element->codeRange.start };
										value->valuePosition = { {resource},text->content.codeRange.start };
										value->valuePosition.column += 9; // <![CDATA[
										eventHandlers.Add(GlobalStringKey::Get(name->name), value);
									}
									goto EVENT_SUCCESS;
								}
								errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"Event script should be contained in a text or CDATA section."));
							EVENT_SUCCESS:;
							}
						}
					}
				}
			}
		}

		void GuiInstanceContext::FillAttSetter(Ptr<GuiResourceItem> resource, Ptr<GuiAttSetterRepr> setter, Ptr<glr::xml::XmlElement> xml, GuiResourceError::List& errors)
		{
			if (auto parser = GetParserManager()->GetParser<ElementName>(L"INSTANCE-ELEMENT-NAME"))
			{
				setter->tagPosition = { {resource},xml->codeRange.start };

				// collect attributes as setters
				for (auto att : xml->attributes)
				{
					if(auto name = parser->Parse({ resource }, att->name.value, att->name.codeRange.start, errors))
					{
						if (name->IsReferenceAttributeName())
						{
							// collect reference attributes
							if (name->name == L"Name")
							{
								setter->instanceName = GlobalStringKey::Get(att->value.value);
							}
						}
						else if (name->IsEnvironmentAttributeName())
						{
							// collect environment variables
							if (setter->environmentVariables.Keys().Contains(GlobalStringKey::Get(name->name)))
							{
								errors.Add(GuiResourceError({ {resource},att->name.codeRange.start }, L"Duplicated environment variable \"" + name->name + L"\"."));
							}
							else
							{
								auto value = Ptr(new GuiAttSetterRepr::EnvVarValue);
								value->value = att->value.value;
								value->attPosition = { {resource},att->codeRange.start };
								value->valuePosition = { {resource},att->value.codeRange.start };
								value->valuePosition.column += 1;
								setter->environmentVariables.Add(GlobalStringKey::Get(name->name), value);
							}
						}
						else if (name->IsPropertyAttributeName())
						{
							// collect attributes setters
							if (setter->setters.Keys().Contains(GlobalStringKey::Get(name->name)))
							{
								errors.Add(GuiResourceError({ {resource},att->name.codeRange.start }, L"Duplicated property \"" + name->name + L"\"."));
							}
							else
							{
								auto sv = Ptr(new GuiAttSetterRepr::SetterValue);
								sv->binding = GlobalStringKey::Get(name->binding);
								sv->attPosition = { {resource},att->codeRange.start };
								setter->setters.Add(GlobalStringKey::Get(name->name), sv);

								auto value = Ptr(new GuiTextRepr);
								value->text = att->value.value;
								value->tagPosition = { {resource},att->value.codeRange.start };
								value->tagPosition.column += 1;
								sv->values.Add(value);
							}
						}
						else if (name->IsEventAttributeName())
						{
							// collect event setters
							if (setter->eventHandlers.Keys().Contains(GlobalStringKey::Get(name->name)))
							{
								errors.Add(GuiResourceError({ {resource},att->name.codeRange.start }, L"Duplicated event \"" + name->name + L"\"."));
							}
							else
							{
								auto value = Ptr(new GuiAttSetterRepr::EventValue);
								value->binding = GlobalStringKey::Get(name->binding);
								value->value = att->value.value;
								value->attPosition = { {resource},att->codeRange.start };
								value->valuePosition = { {resource},att->value.codeRange.start };
								value->valuePosition.column += 1;
								setter->eventHandlers.Add(GlobalStringKey::Get(name->name), value);
							}
						}
						else
						{
							errors.Add(GuiResourceError({ {resource},att->name.codeRange.start }, L"Unknown attribute name: \"" + att->name.value + L"\"."));
						}
					}
				}

				// collect attributes and events
				CollectAttributes(resource, setter->setters, xml, errors);
				CollectEvents(resource, setter->eventHandlers, xml, errors);
			}
		}

		Ptr<GuiConstructorRepr> GuiInstanceContext::LoadCtor(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlElement> xml, GuiResourceError::List& errors)
		{
			if (auto parser = GetParserManager()->GetParser<ElementName>(L"INSTANCE-ELEMENT-NAME"))
			{
				if(auto ctorName = parser->Parse({ resource }, xml->name.value, xml->name.codeRange.start, errors))
				{
					if (ctorName->IsCtorName())
					{
						auto ctor = Ptr(new GuiConstructorRepr);
						ctor->typeNamespace = GlobalStringKey::Get(ctorName->namespaceName);
						ctor->typeName = GlobalStringKey::Get(ctorName->name);
						// collect attributes as setters
						for (auto att : xml->attributes)
						{
							if(auto attName = parser->Parse({ resource }, att->name.value, att->name.codeRange.start, errors))
							{
								if (attName->IsReferenceAttributeName())
								{
									if (attName->name == L"Style")
									{
										ctor->styleName = att->value.value;
									}
								}
							}
						}
						FillAttSetter(resource, ctor, xml, errors);
						return ctor;
					}
					else
					{
						errors.Add(GuiResourceError({ {resource},xml->codeRange.start }, L"Wrong constructor name \"" + xml->name.value + L"\"."));
					}
				}
			}
			return 0;
		}

		Ptr<GuiInstanceContext> GuiInstanceContext::LoadFromXml(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlDocument> xml, GuiResourceError::List& errors)
		{
			auto context = Ptr(new GuiInstanceContext);
			context->tagPosition = { {resource},xml->rootElement->codeRange.start };

			if (xml->rootElement->name.value == L"Instance")
			{
				if (auto codeBehindAttr = XmlGetAttribute(xml->rootElement, L"ref.CodeBehind"))
				{
					context->codeBehind = codeBehindAttr->value.value == L"true";
				}

				// load type name
				if (auto classAttr = XmlGetAttribute(xml->rootElement, L"ref.Class"))
				{
					context->className = classAttr->value.value;
					context->classPosition = { {resource},classAttr->codeRange.start };
				}

				// load style names
				if (auto styleAttr = XmlGetAttribute(xml->rootElement, L"ref.Styles"))
				{
					SplitBySemicolon(styleAttr->value.value, context->stylePaths);
					context->stylePosition = { {resource},styleAttr->codeRange.start };
				}

				// load namespaces
				List<Ptr<XmlAttribute>> namespaceAttributes;
				CopyFrom(namespaceAttributes, xml->rootElement->attributes);
				if (!XmlGetAttribute(xml->rootElement, L"xmlns"))
				{
					auto att = Ptr(new XmlAttribute);
					att->name.value = L"xmlns";
					att->value.value =
						L"presentation::controls::Gui*;"
						L"presentation::elements::Gui*Element;"
						L"presentation::compositions::Gui*Composition;"
						L"presentation::compositions::Gui*;"
						L"presentation::templates::Gui*;"
						L"system::*;"
						L"system::reflection::*;"
						L"presentation::*;"
						L"presentation::Gui*;"
						L"presentation::controls::*;"
						L"presentation::controls::list::*;"
						L"presentation::controls::tree::*;"
						L"presentation::elements::*;"
						L"presentation::elements::Gui*;"
						L"presentation::elements::text::*;"
						L"presentation::compositions::*;"
						L"presentation::templates::*;"
						L"presentation::theme::*";
					namespaceAttributes.Add(att);
				}
				for (auto att : namespaceAttributes)
				{
					// check if the attribute defines a namespace
					WString attName = att->name.value;
					if (attName.Length() >= 5 && attName.Left(5) == L"xmlns")
					{
						GlobalStringKey ns;
						if (attName.Length() > 6)
						{
							if (attName.Left(6) == L"xmlns:")
							{
								ns = GlobalStringKey::Get(attName.Sub(6, attName.Length() - 6));
							}
							else
							{
								continue;
							}
						}

						// create a data structure for the namespace
						Ptr<NamespaceInfo> info;
						vint index = context->namespaces.Keys().IndexOf(ns);
						if (index == -1)
						{
							info = Ptr(new NamespaceInfo);
							info->name = ns;
							info->attPosition = { {resource},att->codeRange.start };
							context->namespaces.Add(ns, info);
						}
						else
						{
							info = context->namespaces.Values()[index];
						}

						// extract all patterns in the namespace, split the value by ';'
						List<WString> patterns;
						SplitBySemicolon(att->value.value, patterns);
						for (auto pattern : patterns)
						{
							// add the pattern to the namespace
							auto ns = Ptr(new GuiInstanceNamespace);
							Pair<vint, vint> star = INVLOC.FindFirst(pattern, L"*", Locale::None);
							if (star.key == -1)
							{
								ns->prefix = pattern;
							}
							else
							{
								ns->prefix = pattern.Sub(0, star.key);
								ns->postfix = pattern.Sub(star.key + star.value, pattern.Length() - star.key - star.value);
							}
							info->namespaces.Add(ns);
						}
					}
				}

				// load instance
				for (auto element : XmlGetElements(xml->rootElement))
				{
					if (element->name.value == L"ref.Parameter")
					{
						auto attName = XmlGetAttribute(element, L"Name");
						auto attClass = XmlGetAttribute(element, L"Class");
						if (attName && attClass)
						{
							auto parameter = Ptr(new GuiInstanceParameter);
							parameter->name = GlobalStringKey::Get(attName->value.value);
							parameter->className = GlobalStringKey::Get(attClass->value.value);
							parameter->tagPosition = { {resource},element->codeRange.start };
							parameter->classPosition = { {resource},attClass->value.codeRange.start };
							parameter->classPosition.column += 1;
							context->parameters.Add(parameter);
						}
						else
						{
							errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"ref.Parameter requires the following attributes existing at the same time: Name, Class."));
						}
					}
					else if (element->name.value == L"ref.LocalizedStrings")
					{
						auto attName = XmlGetAttribute(element, L"Name");
						auto attClass = XmlGetAttribute(element, L"Class");
						auto attDefault = XmlGetAttribute(element, L"Default");
						if (attName && attClass)
						{
							auto localized = Ptr(new GuiInstanceLocalized);
							localized->name = GlobalStringKey::Get(attName->value.value);
							localized->className = GlobalStringKey::Get(attClass->value.value);
							localized->tagPosition = { { resource },element->codeRange.start };
							localized->classPosition = { { resource },attClass->value.codeRange.start };
							localized->classPosition.column += 1;

							if (attDefault)
							{
								localized->defaultStrings = attDefault->value.value == L"true";
							}
							context->localizeds.Add(localized);
						}
						else
						{
							errors.Add(GuiResourceError({ { resource },element->codeRange.start }, L"ref.LocalizedStrings requires the following attributes existing at the same time: Name, Class."));
						}
					}

#define COLLECT_SCRIPT(NAME, SCRIPT, POSITION)\
					(element->name.value == L"ref." #NAME)\
					{\
						if (element->subNodes.Count() == 1)\
						{\
							if (auto cdata = element->subNodes[0].Cast<XmlCData>())\
							{\
								context->SCRIPT = cdata->content.value;\
								context->POSITION = { {resource},cdata->codeRange.start };\
								context->POSITION.column += 9; /* <![CDATA[ */\
								goto NAME##_SCRIPT_SUCCESS;\
							}\
						}\
						errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"Script should be contained in a CDATA section."));\
					NAME##_SCRIPT_SUCCESS:;\
					}\

					else if COLLECT_SCRIPT(Members, memberScript, memberPosition)
					else if COLLECT_SCRIPT(Ctor, ctorScript, ctorPosition)
					else if COLLECT_SCRIPT(Dtor, dtorScript, dtorPosition)

#undef COLLECT_SCRIPT
					else if (!context->instance)
					{
						context->instance = LoadCtor(resource, element, errors);
					}
				}
			}
			else
			{
				errors.Add(GuiResourceError({ {resource},xml->rootElement->codeRange.start }, L"The root element of instance should be \"Instance\"."));
			}

			return context->instance ? context : nullptr;
		}

		Ptr<glr::xml::XmlDocument> GuiInstanceContext::SaveToXml()
		{
			auto xmlInstance = Ptr(new XmlElement);
			xmlInstance->name.value = L"Instance";

			{
				auto attCodeBehind = Ptr(new XmlAttribute);
				attCodeBehind->name.value = L"ref.CodeBehind";
				attCodeBehind->value.value = codeBehind ? L"true" : L"false";
				xmlInstance->attributes.Add(attCodeBehind);
			}

			auto attClass = Ptr(new XmlAttribute);
			attClass->name.value = L"ref.Class";
			attClass->value.value = className;
			xmlInstance->attributes.Add(attClass);

			// TODO: (enumerable) foreach on dictionary
			for (vint i = 0; i < namespaces.Count(); i++)
			{
				auto key = namespaces.Keys()[i];
				auto value = namespaces.Values()[i];

				auto xmlns = Ptr(new XmlAttribute);
				xmlns->name.value = L"xmlns";
				if (key != GlobalStringKey::Empty)
				{
					xmlns->name.value += L":" + key.ToString();
				}
				xmlInstance->attributes.Add(xmlns);

				// TODO: (enumerable) Linq:Aggregate
				for (vint j = 0; j < value->namespaces.Count(); j++)
				{
					auto ns = value->namespaces[j];
					if (j != 0)
					{
						xmlns->value.value += L";";
					}
					xmlns->value.value += ns->prefix + L"*" + ns->postfix;
				}
			}

			for (auto parameter : parameters)
			{
				auto xmlParameter = Ptr(new XmlElement);
				xmlParameter->name.value = L"ref.Parameter";
				xmlInstance->subNodes.Add(xmlParameter);

				auto attName = Ptr(new XmlAttribute);
				attName->name.value = L"Name";
				attName->value.value = parameter->name.ToString();
				xmlParameter->attributes.Add(attName);

				auto attClass = Ptr(new XmlAttribute);
				attClass->name.value = L"Class";
				attClass->value.value = parameter->className.ToString();
				xmlParameter->attributes.Add(attClass);
			}

			for (auto localized : localizeds)
			{
				auto xmlParameter = Ptr(new XmlElement);
				xmlParameter->name.value = L"ref.LocalizedStrings";
				xmlInstance->subNodes.Add(xmlParameter);

				auto attName = Ptr(new XmlAttribute);
				attName->name.value = L"Name";
				attName->value.value = localized->name.ToString();
				xmlParameter->attributes.Add(attName);

				auto attClass = Ptr(new XmlAttribute);
				attClass->name.value = L"Class";
				attClass->value.value = localized->className.ToString();
				xmlParameter->attributes.Add(attClass);

				auto attDefault = Ptr(new XmlAttribute);
				attDefault->name.value = L"Default";
				attDefault->value.value = localized->defaultStrings ? L"true" : L"false";
				xmlParameter->attributes.Add(attDefault);
			}

#define SERIALIZE_SCRIPT(NAME, SCRIPT)\
			if (SCRIPT != L"")\
			{\
				auto xmlScript = Ptr(new XmlElement);\
				xmlScript->name.value = L"ref." #NAME;\
				xmlInstance->subNodes.Add(xmlScript);\
				auto text = Ptr(new XmlCData);\
				text->content.value = SCRIPT;\
				xmlScript->subNodes.Add(text);\
			}\

			SERIALIZE_SCRIPT(Members, memberScript)
			SERIALIZE_SCRIPT(Ctpr, ctorScript)
			SERIALIZE_SCRIPT(Dtor, dtorScript)

#undef SERIALIZE_SCRIPT

			if (stylePaths.Count() > 0)
			{
				auto attStyles = Ptr(new XmlAttribute);
				attStyles->name.value = L"ref.Styles";
				xmlInstance->attributes.Add(attStyles);

				// TODO: (enumerable) Linq:Aggregate
				for (vint j = 0; j < stylePaths.Count(); j++)
				{
					if (j != 0)
					{
						attStyles->value.value += L";";
					}
					attStyles->value.value += stylePaths[j];
				}
			}

			instance->FillXml(xmlInstance);

			auto doc = Ptr(new XmlDocument);
			doc->rootElement = xmlInstance;
			return doc;
		}

		bool GuiInstanceContext::ApplyStyles(Ptr<GuiResourceItem> resource, Ptr<GuiResourcePathResolver> resolver, GuiResourceError::List& errors)
		{
			if (!appliedStyles)
			{
				appliedStyles = true;

				List<Ptr<GuiInstanceStyle>> styles;
				for (auto uri : stylePaths)
				{
					WString protocol, path;
					if (IsResourceUrl(uri, protocol, path))
					{
						if (auto styleContext = resolver->ResolveResource(protocol, path).Cast<GuiInstanceStyleContext>())
						{
							CopyFrom(styles, styleContext->styles, true);
						}
						else
						{
							errors.Add(GuiResourceError({ resource }, stylePosition, L"Failed to find the style referred in attribute \"ref.Styles\": \"" + uri + L"\"."));
						}
					}
					else
					{
						errors.Add(GuiResourceError({ resource }, stylePosition, L"Invalid path in attribute \"ref.Styles\": \"" + uri + L"\"."));
					}
				}

				for (auto style : styles)
				{
					List<Ptr<GuiConstructorRepr>> output;
					ExecuteQuery(style->query, Ptr(this), output);
					for (auto ctor : output)
					{
						ApplyStyle(style, ctor);
					}
				}

				return true;
			}
			else
			{
				return false;
			}
		}

/***********************************************************************
GuiInstanceStyle
***********************************************************************/

		namespace visitors
		{
			class SetStyleMarkVisitor : public Object, public GuiValueRepr::IVisitor
			{
			public:
				void Visit(GuiTextRepr* repr)override
				{
					repr->fromStyle = true;
				}

				void Visit(GuiAttSetterRepr* repr)override
				{
					repr->fromStyle = true;
					for (auto value : repr->setters.Values())
					{
						for (auto subValue : value->values)
						{
							subValue->Accept(this);
						}
					}
					for (auto value : repr->eventHandlers.Values())
					{
						value->fromStyle = true;
					}
					for (auto value : repr->environmentVariables.Values())
					{
						value->fromStyle = true;
					}
				}

				void Visit(GuiConstructorRepr* repr)override
				{
					Visit((GuiAttSetterRepr*)repr);
				}
			};
		}
		using namespace visitors;

		Ptr<GuiInstanceStyle> GuiInstanceStyle::LoadFromXml(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlElement> xml, GuiResourceError::List& errors)
		{
			auto style = Ptr(new GuiInstanceStyle);
			if (auto pathAttr = XmlGetAttribute(xml, L"ref.Path"))
			{
				auto position = pathAttr->value.codeRange.start;
				position.column += 1;

				auto parser = GetParserManager()->GetParser<instancequery::GuiIqQuery>(L"INSTANCE-QUERY");
				auto query = parser->Parse({ resource }, pathAttr->value.value, position, errors);
				if (!query) return nullptr;
				style->query = query;
			}
			else
			{
				errors.Add(GuiResourceError({ {resource},xml->codeRange.start }, L"Missing attribute \"ref.Path\" in <Style>."));
			}
			style->setter = Ptr(new GuiAttSetterRepr);
			GuiInstanceContext::FillAttSetter(resource, style->setter, xml, errors);

			SetStyleMarkVisitor visitor;
			style->setter->Accept(&visitor);
			return style;
		}

		Ptr<glr::xml::XmlElement> GuiInstanceStyle::SaveToXml()
		{
			auto xmlStyle = Ptr(new XmlElement);
			xmlStyle->name.value = L"Style";

			auto attPath = Ptr(new XmlAttribute);
			attPath->name.value = L"ref.Path";
			attPath->value.value = GenerateToStream([&](StreamWriter& writer)
			{
				GuiIqPrint(query, writer);
			});
			xmlStyle->attributes.Add(attPath);

			setter->FillXml(xmlStyle);
			return xmlStyle;
		}

/***********************************************************************
GuiInstanceStyleContext
***********************************************************************/

		Ptr<GuiInstanceStyleContext> GuiInstanceStyleContext::LoadFromXml(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlDocument> xml, GuiResourceError::List& errors)
		{
			auto context = Ptr(new GuiInstanceStyleContext);
			if (xml->rootElement->name.value == L"Styles")
			{
				for (auto styleElement : XmlGetElements(xml->rootElement))
				{
					if (styleElement->name.value == L"Style")
					{
						if (auto style = GuiInstanceStyle::LoadFromXml(resource, styleElement, errors))
						{
							context->styles.Add(style);
						}
					}
					else
					{
						errors.Add(GuiResourceError({ {resource},styleElement->codeRange.start }, L"Unknown element in <Styles>: \"" + styleElement->name.value + L"\"."));
					}
				}
			}
			else
			{
				errors.Add(GuiResourceError({ {resource},xml->rootElement->codeRange.start }, L"The root element of instance styles should be \"Styles\"."));
			}
			return context;
		}

		Ptr<glr::xml::XmlDocument> GuiInstanceStyleContext::SaveToXml()
		{
			auto xmlStyles = Ptr(new XmlElement);
			xmlStyles->name.value = L"Styles";

			for (auto style : styles)
			{
				xmlStyles->subNodes.Add(style->SaveToXml());
			}

			auto doc = Ptr(new XmlDocument);
			doc->rootElement = xmlStyles;
			return doc;
		}
	}
}

/***********************************************************************
.\GUIINSTANCESHAREDSCRIPT.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace glr::xml;

/***********************************************************************
GuiInstanceSharedScript
***********************************************************************/

		Ptr<GuiInstanceSharedScript> GuiInstanceSharedScript::LoadFromXml(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlDocument> xml, GuiResourceError::List& errors)
		{
			if (xml->rootElement->subNodes.Count() == 1)
			{
				if (auto cdata = xml->rootElement->subNodes[0].Cast<XmlCData>())
				{
					auto script = Ptr(new GuiInstanceSharedScript);
					script->language = xml->rootElement->name.value;
					script->code = cdata->content.value;
					script->codePosition = { {resource},cdata->codeRange.start };
					script->codePosition.column += 9; // <![CDATA[
					return script;
				}
			}
			errors.Add(GuiResourceError({ {resource},xml->rootElement->codeRange.start }, L"Script should be contained in a CDATA section."));
			return nullptr;
		}

		Ptr<glr::xml::XmlElement> GuiInstanceSharedScript::SaveToXml()
		{
			auto cdata = Ptr(new XmlCData);
			cdata->content.value = code;

			auto xml = Ptr(new XmlElement);
			xml->name.value = language;
			xml->subNodes.Add(cdata);

			return xml;
		}
	}
}

/***********************************************************************
.\INSTANCELOADERS\GUIINSTANCELOADER_COMPOSITIONS.CPP
***********************************************************************/

#ifndef VCZH_DEBUG_NO_REFLECTION

namespace vl
{
	namespace presentation
	{
		namespace instance_loaders
		{

/***********************************************************************
GuiAxisInstanceLoader
***********************************************************************/

			class GuiAxisInstanceLoader : public Object, public IGuiInstanceLoader
			{
			protected:
				GlobalStringKey					typeName;
				GlobalStringKey					_AxisDirection;

			public:
				GuiAxisInstanceLoader()
				{
					typeName = GlobalStringKey::Get(description::TypeInfo<GuiAxis>::content.typeName);
					_AxisDirection = GlobalStringKey::Get(L"AxisDirection");
				}

				GlobalStringKey GetTypeName()override
				{
					return typeName;
				}

				void GetRequiredPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					if (CanCreate(typeInfo))
					{
						propertyNames.Add(_AxisDirection);
					}
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					GetRequiredPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _AxisDirection)
					{
						auto info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<AxisDirection>::CreateTypeInfo());
						info->usage = GuiInstancePropertyInfo::ConstructorArgument;
						return info;
					}
					return IGuiInstanceLoader::GetPropertyType(precompileContext, propertyInfo);
				}

				bool CanCreate(const TypeInfo& typeInfo)override
				{
					return typeName == typeInfo.typeName;
				}

				Ptr<workflow::WfStatement> CreateInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)override
				{
					if (CanCreate(typeInfo))
					{
						vint indexAxisDirection = arguments.Keys().IndexOf(_AxisDirection);
						if (indexAxisDirection != -1)
						{
							auto createExpr = Ptr(new WfNewClassExpression);
							createExpr->type = GetTypeFromTypeInfo(TypeInfoRetriver<Ptr<GuiAxis>>::CreateTypeInfo().Obj());
							createExpr->arguments.Add(arguments.GetByIndex(indexAxisDirection)[0].expression);

							auto refVariable = Ptr(new WfReferenceExpression);
							refVariable->name.value = variableName.ToString();

							auto assignExpr = Ptr(new WfBinaryExpression);
							assignExpr->op = WfBinaryOperator::Assign;
							assignExpr->first = refVariable;
							assignExpr->second = createExpr;

							auto assignStat = Ptr(new WfExpressionStatement);
							assignStat->expression = assignExpr;
							return assignStat;
						}
					}
					return nullptr;
				}
			};

/***********************************************************************
GuiCompositionInstanceLoader
***********************************************************************/

			class GuiCompositionInstanceLoader : public Object, public IGuiInstanceLoader
			{
			protected:
				GlobalStringKey					typeName;

			public:
				GuiCompositionInstanceLoader()
				{
					typeName = GlobalStringKey::Get(description::TypeInfo<GuiGraphicsComposition>::content.typeName);
				}

				GlobalStringKey GetTypeName()override
				{
					return typeName;
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					propertyNames.Add(GlobalStringKey::Empty);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == GlobalStringKey::Empty)
					{
						auto info = GuiInstancePropertyInfo::Collection(nullptr);
						info->acceptableTypes.Add(TypeInfoRetriver<GuiControl*>::CreateTypeInfo());
						info->acceptableTypes.Add(TypeInfoRetriver<GuiGraphicsComposition*>::CreateTypeInfo());
						info->acceptableTypes.Add(TypeInfoRetriver<Ptr<IGuiGraphicsElement>>::CreateTypeInfo());
						if (propertyInfo.typeInfo.typeInfo->GetTypeDescriptor()->CanConvertTo(description::GetTypeDescriptor<GuiInstanceRootObject>()))
						{
							info->acceptableTypes.Add(TypeInfoRetriver<GuiComponent*>::CreateTypeInfo());
						}
						return info;
					}
					return IGuiInstanceLoader::GetPropertyType(precompileContext, propertyInfo);
				}

				Ptr<workflow::WfStatement> AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
				{
					auto block = Ptr(new WfBlockStatement);

					// TODO: (enumerable) foreach on group
					for (auto [prop, index] : indexed(arguments.Keys()))
					{
						const auto& values = arguments.GetByIndex(index);
						if (prop == GlobalStringKey::Empty)
						{
							auto value = values[0].expression;
							auto td = values[0].typeInfo->GetTypeDescriptor();

							Ptr<WfExpression> expr;
							if (td->CanConvertTo(description::GetTypeDescriptor<GuiComponent>()))
							{
								auto refControl = Ptr(new WfReferenceExpression);
								refControl->name.value = variableName.ToString();

								auto refAddComponent = Ptr(new WfMemberExpression);
								refAddComponent->parent = refControl;
								refAddComponent->name.value = L"AddComponent";

								auto call = Ptr(new WfCallExpression);
								call->function = refAddComponent;
								call->arguments.Add(value);

								expr = call;
							}
							else if (td->CanConvertTo(description::GetTypeDescriptor<GuiControlHost>()))
							{
								auto refControl = Ptr(new WfReferenceExpression);
								refControl->name.value = variableName.ToString();

								auto refAddControlHostComponent = Ptr(new WfMemberExpression);
								refAddControlHostComponent->parent = refControl;
								refAddControlHostComponent->name.value = L"AddControlHostComponent";

								auto call = Ptr(new WfCallExpression);
								call->function = refAddControlHostComponent;
								call->arguments.Add(value);

								expr = call;
							}
							else if (td->CanConvertTo(description::GetTypeDescriptor<IGuiGraphicsElement>()))
							{
								auto refComposition = Ptr(new WfReferenceExpression);
								refComposition->name.value = variableName.ToString();

								auto refOwnedElement = Ptr(new WfMemberExpression);
								refOwnedElement->parent = refComposition;
								refOwnedElement->name.value = L"OwnedElement";

								auto assign = Ptr(new WfBinaryExpression);
								assign->op = WfBinaryOperator::Assign;
								assign->first = refOwnedElement;
								assign->second = value;

								expr = assign;
							}
							else if (td->CanConvertTo(description::GetTypeDescriptor<GuiControl>()))
							{
								auto refBoundsComposition = Ptr(new WfMemberExpression);
								refBoundsComposition->parent = value;
								refBoundsComposition->name.value = L"BoundsComposition";

								auto refComposition = Ptr(new WfReferenceExpression);
								refComposition->name.value = variableName.ToString();

								auto refAddChild = Ptr(new WfMemberExpression);
								refAddChild->parent = refComposition;
								refAddChild->name.value = L"AddChild";

								auto call = Ptr(new WfCallExpression);
								call->function = refAddChild;
								call->arguments.Add(refBoundsComposition);

								expr = call;
							}
							else if (td->CanConvertTo(description::GetTypeDescriptor<GuiGraphicsComposition>()))
							{
								auto refComposition = Ptr(new WfReferenceExpression);
								refComposition->name.value = variableName.ToString();

								auto refAddChild = Ptr(new WfMemberExpression);
								refAddChild->parent = refComposition;
								refAddChild->name.value = L"AddChild";

								auto call = Ptr(new WfCallExpression);
								call->function = refAddChild;
								call->arguments.Add(value);

								expr = call;
							}

							if (expr)
							{
								auto stat = Ptr(new WfExpressionStatement);
								stat->expression = expr;
								block->statements.Add(stat);
							}
						}
					}

					if (block->statements.Count() > 0)
					{
						return block;
					}
					return nullptr;
				}
			};

/***********************************************************************
GuiTableCompositionInstanceLoader
***********************************************************************/

			class GuiTableCompositionInstanceLoader : public Object, public IGuiInstanceLoader
			{
			protected:
				GlobalStringKey					typeName;
				GlobalStringKey					_Rows, _Columns;

			public:
				GuiTableCompositionInstanceLoader()
				{
					typeName = GlobalStringKey::Get(description::TypeInfo<GuiTableComposition>::content.typeName);
					_Rows = GlobalStringKey::Get(L"Rows");
					_Columns = GlobalStringKey::Get(L"Columns");
				}

				GlobalStringKey GetTypeName()override
				{
					return typeName;
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					propertyNames.Add(_Rows);
					propertyNames.Add(_Columns);
				}

				void GetPairedProperties(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					if (propertyInfo.propertyName == _Rows || propertyInfo.propertyName == _Columns)
					{
						propertyNames.Add(_Rows);
						propertyNames.Add(_Columns);
					}
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _Rows || propertyInfo.propertyName == _Columns)
					{
						return GuiInstancePropertyInfo::Array(TypeInfoRetriver<GuiCellOption>::CreateTypeInfo());
					}
					return IGuiInstanceLoader::GetPropertyType(precompileContext, propertyInfo);
				}

				Ptr<workflow::WfStatement> AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
				{
					auto block = Ptr(new WfBlockStatement);

					// TODO: (enumerable) foreach on group
					for (auto [prop, index] : indexed(arguments.Keys()))
					{
						if (prop == _Rows)
						{
							auto indexColumns = arguments.Keys().IndexOf(_Columns);
							if (indexColumns != -1)
							{
								auto& rows = arguments.GetByIndex(index);
								auto& columns = arguments.GetByIndex(indexColumns);

								{
									auto refComposition = Ptr(new WfReferenceExpression);
									refComposition->name.value = variableName.ToString();

									auto refSetRowsAndColumns = Ptr(new WfMemberExpression);
									refSetRowsAndColumns->parent = refComposition;
									refSetRowsAndColumns->name.value = L"SetRowsAndColumns";

									auto rowsExpr = Ptr(new WfIntegerExpression);
									rowsExpr->value.value = itow(rows.Count());

									auto columnsExpr = Ptr(new WfIntegerExpression);
									columnsExpr->value.value = itow(columns.Count());

									auto call = Ptr(new WfCallExpression);
									call->function = refSetRowsAndColumns;
									call->arguments.Add(rowsExpr);
									call->arguments.Add(columnsExpr);

									auto stat = Ptr(new WfExpressionStatement);
									stat->expression = call;
									block->statements.Add(stat);
								}

								// TODO: (enumerable) foreach:indexed
								for (vint i = 0; i < rows.Count(); i++)
								{
									auto refComposition = Ptr(new WfReferenceExpression);
									refComposition->name.value = variableName.ToString();

									auto refSetRowOption = Ptr(new WfMemberExpression);
									refSetRowOption->parent = refComposition;
									refSetRowOption->name.value = L"SetRowOption";

									auto indexExpr = Ptr(new WfIntegerExpression);
									indexExpr->value.value = itow(i);

									auto call = Ptr(new WfCallExpression);
									call->function = refSetRowOption;
									call->arguments.Add(indexExpr);
									call->arguments.Add(rows[i].expression);

									auto stat = Ptr(new WfExpressionStatement);
									stat->expression = call;
									block->statements.Add(stat);
								}

								// TODO: (enumerable) foreach:indexed
								for (vint i = 0; i < columns.Count(); i++)
								{
									auto refComposition = Ptr(new WfReferenceExpression);
									refComposition->name.value = variableName.ToString();

									auto refSetColumnOption = Ptr(new WfMemberExpression);
									refSetColumnOption->parent = refComposition;
									refSetColumnOption->name.value = L"SetColumnOption";

									auto indexExpr = Ptr(new WfIntegerExpression);
									indexExpr->value.value = itow(i);

									auto call = Ptr(new WfCallExpression);
									call->function = refSetColumnOption;
									call->arguments.Add(indexExpr);
									call->arguments.Add(columns[i].expression);

									auto stat = Ptr(new WfExpressionStatement);
									stat->expression = call;
									block->statements.Add(stat);
								}
							}
						}
					}

					if (block->statements.Count() > 0)
					{
						return block;
					}
					return nullptr;
				}
			};

/***********************************************************************
GuiCellCompositionInstanceLoader
***********************************************************************/

			class GuiCellCompositionInstanceLoader : public Object, public IGuiInstanceLoader
			{
			protected:
				GlobalStringKey					typeName;
				GlobalStringKey					_Site;

			public:
				GuiCellCompositionInstanceLoader()
				{
					typeName = GlobalStringKey::Get(description::TypeInfo<GuiCellComposition>::content.typeName);
					_Site = GlobalStringKey::Get(L"Site");
				}

				GlobalStringKey GetTypeName()override
				{
					return typeName;
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					propertyNames.Add(_Site);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _Site)
					{
						return GuiInstancePropertyInfo::Assign(TypeInfoRetriver<SiteValue>::CreateTypeInfo());
					}
					return IGuiInstanceLoader::GetPropertyType(precompileContext, propertyInfo);
				}

				Ptr<workflow::WfStatement> AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
				{
					auto block = Ptr(new WfBlockStatement);

					// TODO: (enumerable) foreach on group
					for (auto [prop, index] : indexed(arguments.Keys()))
					{
						if (prop == _Site)
						{
							SiteValue site;
							{
								auto siteExpr = arguments.GetByIndex(index)[0].expression;
								if (auto inferExpr = siteExpr.Cast<WfInferExpression>())
								{
									if (auto ctorExpr = inferExpr->expression.Cast<WfConstructorExpression>())
									{
										auto st = description::GetTypeDescriptor<vint>()->GetSerializableType();
										for (auto argument : ctorExpr->arguments)
										{
											if (auto keyExpr = argument->key.Cast<WfReferenceExpression>())
											{
												if (auto valueExpr = argument->value.Cast<WfIntegerExpression>())
												{
													Value value;
													if (st->Deserialize(valueExpr->value.value, value))
													{
														vint propValue = UnboxValue<vint>(value);
														if (keyExpr->name.value == L"row")
														{
															site.row = propValue;
														}
														else if (keyExpr->name.value == L"column")
														{
															site.column = propValue;
														}
														else if (keyExpr->name.value == L"rowSpan")
														{
															site.rowSpan = propValue;
														}
														else if (keyExpr->name.value == L"columnSpan")
														{
															site.columnSpan = propValue;
														}
														else
														{
															goto ILLEGAL_SITE_PROPERTY;
														}
														continue;
													}
												}
											}
											goto ILLEGAL_SITE_PROPERTY;
										}
										goto FINISH_SITE_PROPERTY;
									}
								}
							ILLEGAL_SITE_PROPERTY:
								errors.Add(GuiResourceError({ resolvingResult.resource }, attPosition,
									L"Precompile: The value of property \"Site\" of type \"" +
									typeInfo.typeName.ToString() +
									L"\" is not in a correct format: \"row:<integer> column:<integer> [rowSpan:<integer>] [columnSpan:<integer>]\"."));
								continue;
							}
						FINISH_SITE_PROPERTY:;

							{
								auto refComposition = Ptr(new WfReferenceExpression);
								refComposition->name.value = variableName.ToString();

								auto refSetSite = Ptr(new WfMemberExpression);
								refSetSite->parent = refComposition;
								refSetSite->name.value = L"SetSite";

								auto call = Ptr(new WfCallExpression);
								call->function = refSetSite;

								{
									auto arg = Ptr(new WfIntegerExpression);
									arg->value.value = itow(site.row);
									call->arguments.Add(arg);
								}
								{
									auto arg = Ptr(new WfIntegerExpression);
									arg->value.value = itow(site.column);
									call->arguments.Add(arg);
								}
								{
									auto arg = Ptr(new WfIntegerExpression);
									arg->value.value = itow(site.rowSpan);
									call->arguments.Add(arg);
								}
								{
									auto arg = Ptr(new WfIntegerExpression);
									arg->value.value = itow(site.columnSpan);
									call->arguments.Add(arg);
								}

								auto stat = Ptr(new WfExpressionStatement);
								stat->expression = call;
								block->statements.Add(stat);
							}
						}
					}

					if (block->statements.Count() > 0)
					{
						return block;
					}
					return nullptr;
				}
			};

/***********************************************************************
Initialization
***********************************************************************/

			void LoadCompositions(IGuiInstanceLoaderManager* manager)
			{
				manager->SetLoader(Ptr(new GuiAxisInstanceLoader));
				manager->SetLoader(Ptr(new GuiCompositionInstanceLoader));
				manager->SetLoader(Ptr(new GuiTableCompositionInstanceLoader));
				manager->SetLoader(Ptr(new GuiCellCompositionInstanceLoader));
			}
		}
	}
}

#endif


/***********************************************************************
.\INSTANCELOADERS\GUIINSTANCELOADER_DOCUMENT.CPP
***********************************************************************/

#ifndef VCZH_DEBUG_NO_REFLECTION

namespace vl
{
	namespace presentation
	{
		namespace instance_loaders
		{

/***********************************************************************
GuiDocumentItemInstanceLoader
***********************************************************************/

			class GuiDocumentItemInstanceLoader : public Object, public IGuiInstanceLoader
			{
			protected:
				GlobalStringKey					typeName;
				GlobalStringKey					_Name;

			public:
				GuiDocumentItemInstanceLoader()
				{
					typeName = GlobalStringKey::Get(description::TypeInfo<GuiDocumentItem>::content.typeName);
					_Name = GlobalStringKey::Get(L"Name");
				}

				GlobalStringKey GetTypeName()override
				{
					return typeName;
				}

				void GetRequiredPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					if (CanCreate(typeInfo))
					{
						propertyNames.Add(_Name);
					}
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					GetRequiredPropertyNames(precompileContext, typeInfo, propertyNames);
					propertyNames.Add(GlobalStringKey::Empty);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == GlobalStringKey::Empty)
					{
						auto info = GuiInstancePropertyInfo::Collection(nullptr);
						info->acceptableTypes.Add(TypeInfoRetriver<GuiControl*>::CreateTypeInfo());
						info->acceptableTypes.Add(TypeInfoRetriver<GuiGraphicsComposition*>::CreateTypeInfo());
						return info;
					}
					else if (propertyInfo.propertyName == _Name)
					{
						auto info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<WString>::CreateTypeInfo());
						info->usage = GuiInstancePropertyInfo::ConstructorArgument;
						return info;
					}
					return IGuiInstanceLoader::GetPropertyType(precompileContext, propertyInfo);
				}

				
				bool CanCreate(const TypeInfo& typeInfo)override
				{
					return typeName == typeInfo.typeName;
				}

				Ptr<workflow::WfStatement> CreateInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)override
				{
					if (CanCreate(typeInfo))
					{
						vint indexName = arguments.Keys().IndexOf(_Name);	
						if (indexName != -1)
						{
							auto type = TypeInfoRetriver<Ptr<GuiDocumentItem>>::CreateTypeInfo();
							auto createExpr = Ptr(new WfNewClassExpression);
							createExpr->type = GetTypeFromTypeInfo(type.Obj());
							createExpr->arguments.Add(arguments.GetByIndex(indexName)[0].expression);

							auto refVariable = Ptr(new WfReferenceExpression);
							refVariable->name.value = variableName.ToString();

							auto assignExpr = Ptr(new WfBinaryExpression);
							assignExpr->op = WfBinaryOperator::Assign;
							assignExpr->first = refVariable;
							assignExpr->second = createExpr;

							auto assignStat = Ptr(new WfExpressionStatement);
							assignStat->expression = assignExpr;
							return assignStat;
						}
					}
					return nullptr;
				}

				Ptr<workflow::WfStatement> AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
				{
					auto block = Ptr(new WfBlockStatement);

					// TODO: (enumerable) foreach on group
					for (auto [prop, index] : indexed(arguments.Keys()))
					{
						const auto& values = arguments.GetByIndex(index);
						if (prop == GlobalStringKey::Empty)
						{
							auto value = values[0].expression;
							auto td = values[0].typeInfo->GetTypeDescriptor();

							Ptr<WfExpression> compositionExpr;
							if (td->CanConvertTo(description::GetTypeDescriptor<GuiControl>()))
							{
								auto member = Ptr(new WfMemberExpression);
								member->parent = value;
								member->name.value = L"BoundsComposition";
								compositionExpr = member;
							}
							else if (td->CanConvertTo(description::GetTypeDescriptor<GuiGraphicsComposition>()))
							{
								compositionExpr = value;
							}

							if (compositionExpr)
							{
								auto refItem = Ptr(new WfReferenceExpression);
								refItem->name.value = variableName.ToString();

								auto refContainer = Ptr(new WfMemberExpression);
								refContainer->parent = refItem;
								refContainer->name.value = L"Container";

								auto refAddChild = Ptr(new WfMemberExpression);
								refAddChild->parent = refContainer;
								refAddChild->name.value = L"AddChild";

								auto call = Ptr(new WfCallExpression);
								call->function = refAddChild;
								call->arguments.Add(compositionExpr);

								auto stat = Ptr(new WfExpressionStatement);
								stat->expression = call;
								block->statements.Add(stat);
							}
						}
					}

					if (block->statements.Count() > 0)
					{
						return block;
					}
					return nullptr;
				}
			};

/***********************************************************************
GuiDocumentInstanceLoaderBase
***********************************************************************/

			template<typename TBaseType>
			class GuiDocumentInstanceLoaderBase : public TBaseType
			{
			private:
				using TypeInfo = typename TBaseType::TypeInfo;

			protected:
				GlobalStringKey					_Behavior;

				void AddAdditionalArguments(types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, IGuiInstanceLoader::ArgumentMap& arguments, GuiResourceError::List& errors, Ptr<WfNewClassExpression> createControl)override
				{
					vint indexBehavior = arguments.Keys().IndexOf(_Behavior);
					if (indexBehavior != -1)
					{
						createControl->arguments.Add(arguments.GetByIndex(indexBehavior)[0].expression);
					}
				}

			public:
				using PropertyInfo = IGuiInstanceLoader::PropertyInfo;
				using ArgumentMap = IGuiInstanceLoader::ArgumentMap;

				GuiDocumentInstanceLoaderBase(const WString& _typeName, theme::ThemeName themeName)
					:TBaseType(_typeName, themeName)
				{
					_Behavior = GlobalStringKey::Get(L"Behavior");
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					propertyNames.Add(GlobalStringKey::Empty);
					TBaseType::GetPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == GlobalStringKey::Empty)
					{
						return GuiInstancePropertyInfo::CollectionWithParent(TypeInfoRetriver<Ptr<GuiDocumentItem>>::CreateTypeInfo());
					}
					else if(propertyInfo.propertyName == _Behavior && this->CanCreate(propertyInfo.typeInfo))
					{
						auto info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<GuiDocumentConfig>::CreateTypeInfo());
						info->usage = GuiInstancePropertyInfo::ConstructorArgument;
						return info;
					}
					return TBaseType::GetPropertyType(precompileContext, propertyInfo);
				}

				Ptr<workflow::WfStatement> AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
				{
					auto block = Ptr(new WfBlockStatement);

					// TODO: (enumerable) foreach on group
					for (auto [prop, index] : indexed(arguments.Keys()))
					{
						const auto& values = arguments.GetByIndex(index);
						if (prop == GlobalStringKey::Empty)
						{
							auto refControl = Ptr(new WfReferenceExpression);
							refControl->name.value = variableName.ToString();

							auto refAddDocumentItem = Ptr(new WfMemberExpression);
							refAddDocumentItem->parent = refControl;
							refAddDocumentItem->name.value = L"AddDocumentItem";

							auto call = Ptr(new WfCallExpression);
							call->function = refAddDocumentItem;
							call->arguments.Add(values[0].expression);

							auto stat = Ptr(new WfExpressionStatement);
							stat->expression = call;
							block->statements.Add(stat);
						}
					}

					if (block->statements.Count() > 0)
					{
						return block;
					}
					return TBaseType::AssignParameters(precompileContext, resolvingResult, typeInfo, variableName, arguments, attPosition, errors);
				}
			};

/***********************************************************************
GuiDocumentViewerInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiDocumentViewer>
			class GuiDocumentViewerInstanceLoader : public GuiDocumentInstanceLoaderBase<BASE_TYPE>
			{
			public:
				GuiDocumentViewerInstanceLoader()
					:GuiDocumentInstanceLoaderBase<BASE_TYPE>(description::TypeInfo<GuiDocumentViewer>::content.typeName, theme::ThemeName::DocumentViewer)
				{
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiDocumentLabelInstanceLoader
***********************************************************************/
		
#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiDocumentLabel>
			class GuiDocumentLabelInstanceLoader : public GuiDocumentInstanceLoaderBase<BASE_TYPE>
			{
			public:
				GuiDocumentLabelInstanceLoader()
					:GuiDocumentInstanceLoaderBase<BASE_TYPE>(description::TypeInfo<GuiDocumentLabel>::content.typeName, theme::ThemeName::DocumentLabel)
				{
				}
			};
#undef BASE_TYPE

/***********************************************************************
Initialization
***********************************************************************/

			void LoadDocumentControls(IGuiInstanceLoaderManager* manager)
			{
				manager->SetLoader(Ptr(new GuiDocumentItemInstanceLoader));
				manager->SetLoader(Ptr(new GuiDocumentViewerInstanceLoader));
				manager->SetLoader(Ptr(new GuiDocumentLabelInstanceLoader));
				manager->CreateVirtualType(GlobalStringKey::Get(description::TypeInfo<GuiDocumentLabel>::content.typeName),
					Ptr(new GuiDocumentInstanceLoaderBase<GuiTemplateControlInstanceLoader<GuiDocumentLabel>>(
						L"presentation::controls::GuiDocumentTextBox",
						theme::ThemeName::DocumentTextBox
					)));
			}
		}
	}
}

#endif


/***********************************************************************
.\INSTANCELOADERS\GUIINSTANCELOADER_LIST.CPP
***********************************************************************/

#ifndef VCZH_DEBUG_NO_REFLECTION

namespace vl
{
	namespace presentation
	{
		namespace instance_loaders
		{

			template<typename TItemTemplateStyle>
			Ptr<WfStatement> CreateSetControlTemplateStyle(types::ResolvingResult& resolvingResult, GlobalStringKey variableName, Ptr<WfExpression> argument, const WString& propertyName)
			{
				auto createStyle = Ptr(new WfNewClassExpression);
				createStyle->type = GetTypeFromTypeInfo(TypeInfoRetriver<Ptr<TItemTemplateStyle>>::CreateTypeInfo().Obj());
				createStyle->arguments.Add(argument);

				auto refControl = Ptr(new WfReferenceExpression);
				refControl->name.value = variableName.ToString();

				auto refStyleProvider = Ptr(new WfMemberExpression);
				refStyleProvider->parent = refControl;
				refStyleProvider->name.value = propertyName;

				auto assign = Ptr(new WfBinaryExpression);
				assign->op = WfBinaryOperator::Assign;
				assign->first = refStyleProvider;
				assign->second = createStyle;

				auto stat = Ptr(new WfExpressionStatement);
				stat->expression = assign;
				return stat;
			}

/***********************************************************************
GuiComboButtonInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiComboButton>
			class GuiComboButtonInstanceLoader : public BASE_TYPE
			{
			protected:
				GlobalStringKey						_DropdownControl;

				void AddAdditionalArguments(types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceError::List& errors, Ptr<WfNewClassExpression> createControl)override
				{
					vint indexListControl = arguments.Keys().IndexOf(_DropdownControl);
					if (indexListControl != -1)
					{
						createControl->arguments.Add(arguments.GetByIndex(indexListControl)[0].expression);
					}
				}
			public:
				GuiComboButtonInstanceLoader()
					:BASE_TYPE(L"presentation::controls::GuiComboButton", theme::ThemeName::ComboBox)
				{
					_DropdownControl = GlobalStringKey::Get(L"DropdownControl");
				}

				void GetRequiredPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					if (CanCreate(typeInfo))
					{
						propertyNames.Add(_DropdownControl);
					}
					BASE_TYPE::GetRequiredPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					GetRequiredPropertyNames(precompileContext, typeInfo, propertyNames);
					BASE_TYPE::GetPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _DropdownControl)
					{
						auto info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<GuiControl*>::CreateTypeInfo());
						info->usage = GuiInstancePropertyInfo::ConstructorArgument;
						return info;
					}
					return BASE_TYPE::GetPropertyType(precompileContext, propertyInfo);
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiComboBoxInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiComboBoxListControl>
			class GuiComboBoxInstanceLoader : public BASE_TYPE
			{
			protected:
				GlobalStringKey						_ListControl;

				void AddAdditionalArguments(types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceError::List& errors, Ptr<WfNewClassExpression> createControl)override
				{
					vint indexListControl = arguments.Keys().IndexOf(_ListControl);
					if (indexListControl != -1)
					{
						createControl->arguments.Add(arguments.GetByIndex(indexListControl)[0].expression);
					}
				}
			public:
				GuiComboBoxInstanceLoader()
					:BASE_TYPE(L"presentation::controls::GuiComboBox", theme::ThemeName::ComboBox)
				{
					_ListControl = GlobalStringKey::Get(L"ListControl");
				}

				void GetRequiredPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					if (CanCreate(typeInfo))
					{
						propertyNames.Add(_ListControl);
					}
					BASE_TYPE::GetRequiredPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					GetRequiredPropertyNames(precompileContext, typeInfo, propertyNames);
					BASE_TYPE::GetPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _ListControl)
					{
						auto info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<GuiSelectableListControl*>::CreateTypeInfo());
						info->usage = GuiInstancePropertyInfo::ConstructorArgument;
						return info;
					}
					return BASE_TYPE::GetPropertyType(precompileContext, propertyInfo);
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiTreeViewInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiTreeView>
			class GuiTreeViewInstanceLoader : public BASE_TYPE
			{
			protected:
				GlobalStringKey		_Nodes;

			public:
				GuiTreeViewInstanceLoader()
					:BASE_TYPE(description::TypeInfo<GuiTreeView>::content.typeName, theme::ThemeName::TreeView)
				{
					_Nodes = GlobalStringKey::Get(L"Nodes");
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const typename BASE_TYPE::TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					propertyNames.Add(_Nodes);
					BASE_TYPE::GetPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const typename BASE_TYPE::PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _Nodes)
					{
						return GuiInstancePropertyInfo::Collection(TypeInfoRetriver<Ptr<tree::MemoryNodeProvider>>::CreateTypeInfo());
					}
					return BASE_TYPE::GetPropertyType(precompileContext, propertyInfo);
				}

				Ptr<workflow::WfStatement> AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const typename BASE_TYPE::TypeInfo& typeInfo, GlobalStringKey variableName, typename BASE_TYPE::ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
				{
					auto block = Ptr(new WfBlockStatement);

					// TODO: (enumerable) foreach on group
					for (auto [prop, index] : indexed(arguments.Keys()))
					{
						if (prop == _Nodes)
						{
							auto refControl = Ptr(new WfReferenceExpression);
							refControl->name.value = variableName.ToString();

							auto refNodes = Ptr(new WfMemberExpression);
							refNodes->parent = refControl;
							refNodes->name.value = L"Nodes";

							auto refChildren = Ptr(new WfMemberExpression);
							refChildren->parent = refNodes;
							refChildren->name.value = L"Children";

							auto refAdd = Ptr(new WfMemberExpression);
							refAdd->parent = refChildren;
							refAdd->name.value = L"Add";

							auto call = Ptr(new WfCallExpression);
							call->function = refAdd;
							call->arguments.Add(arguments.GetByIndex(index)[0].expression);

							auto stat = Ptr(new WfExpressionStatement);
							stat->expression = call;
							block->statements.Add(stat);
						}
					}

					if (block->statements.Count() > 0)
					{
						return block;
					}
					return BASE_TYPE::AssignParameters(precompileContext, resolvingResult, typeInfo, variableName, arguments, attPosition, errors);
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiBindableTreeViewInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiBindableTreeView>
			class GuiBindableTreeViewInstanceLoader : public BASE_TYPE
			{
			protected:
				GlobalStringKey		_ReverseMappingProperty;

				void AddAdditionalArguments(types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceError::List& errors, Ptr<WfNewClassExpression> createControl)override
				{
					vint indexReverseMappingProperty = arguments.Keys().IndexOf(_ReverseMappingProperty);
					if (indexReverseMappingProperty != -1)
					{
						createControl->arguments.Add(arguments.GetByIndex(indexReverseMappingProperty)[0].expression);
					}
				}
			public:
				GuiBindableTreeViewInstanceLoader()
					:BASE_TYPE(description::TypeInfo<GuiBindableTreeView>::content.typeName, theme::ThemeName::TreeView)
				{
					_ReverseMappingProperty = GlobalStringKey::Get(L"ReverseMappingProperty");
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const typename BASE_TYPE::TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					propertyNames.Add(_ReverseMappingProperty);
					BASE_TYPE::GetPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const typename BASE_TYPE::PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _ReverseMappingProperty)
					{
						auto info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<WritableItemProperty<description::Value>>::CreateTypeInfo());
						info->usage = GuiInstancePropertyInfo::ConstructorArgument;
						return info;
					}
					return BASE_TYPE::GetPropertyType(precompileContext, propertyInfo);
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiTreeNodeInstanceLoader
***********************************************************************/

			class GuiTreeNodeInstanceLoader : public Object, public IGuiInstanceLoader
			{
			protected:
				GlobalStringKey							typeName;
				GlobalStringKey							_Text, _Image, _Tag;

			public:
				GuiTreeNodeInstanceLoader()
					:typeName(GlobalStringKey::Get(L"presentation::controls::tree::TreeNode"))
				{
					_Text = GlobalStringKey::Get(L"Text");
					_Image = GlobalStringKey::Get(L"Image");
					_Tag = GlobalStringKey::Get(L"Tag");
				}

				GlobalStringKey GetTypeName()override
				{
					return typeName;
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					propertyNames.Add(_Text);
					propertyNames.Add(_Image);
					propertyNames.Add(_Tag);
					propertyNames.Add(GlobalStringKey::Empty);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _Text)
					{
						auto info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<WString>::CreateTypeInfo());
						info->usage = GuiInstancePropertyInfo::ConstructorArgument;
						info->bindability = GuiInstancePropertyInfo::Bindable;
						return info;
					}
					else if (propertyInfo.propertyName == _Image)
					{
						auto info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<Ptr<GuiImageData>>::CreateTypeInfo());
						info->usage = GuiInstancePropertyInfo::ConstructorArgument;
						info->bindability = GuiInstancePropertyInfo::Bindable;
						return info;
					}
					else if (propertyInfo.propertyName == _Tag)
					{
						return GuiInstancePropertyInfo::Assign(TypeInfoRetriver<Value>::CreateTypeInfo());
					}
					else if (propertyInfo.propertyName == GlobalStringKey::Empty)
					{
						return GuiInstancePropertyInfo::Collection(TypeInfoRetriver<Ptr<tree::MemoryNodeProvider>>::CreateTypeInfo());
					}
					return IGuiInstanceLoader::GetPropertyType(precompileContext, propertyInfo);
				}

				bool CanCreate(const TypeInfo& typeInfo)override
				{
					return typeInfo.typeName == GetTypeName();
				}

				Ptr<workflow::WfStatement> CreateInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)override
				{
					if (CanCreate(typeInfo))
					{
						auto createItem = Ptr(new WfNewClassExpression);
						createItem->type = GetTypeFromTypeInfo(TypeInfoRetriver<Ptr<tree::TreeViewItem>>::CreateTypeInfo().Obj());

						vint imageIndex = arguments.Keys().IndexOf(_Image);
						vint textIndex = arguments.Keys().IndexOf(_Text);

						if (imageIndex != -1 || textIndex != -1)
						{
							if (imageIndex == -1)
							{
								auto nullExpr = Ptr(new WfLiteralExpression);
								nullExpr->value = WfLiteralValue::Null;
								createItem->arguments.Add(nullExpr);
							}
							else
							{
								createItem->arguments.Add(arguments.GetByIndex(imageIndex)[0].expression);
							}

							if (textIndex == -1)
							{
								createItem->arguments.Add(Ptr(new WfStringExpression));
							}
							else
							{
								createItem->arguments.Add(arguments.GetByIndex(textIndex)[0].expression);
							}
						}

						auto createNode = Ptr(new WfNewClassExpression);
						createNode->type = GetTypeFromTypeInfo(TypeInfoRetriver<Ptr<tree::MemoryNodeProvider>>::CreateTypeInfo().Obj());
						createNode->arguments.Add(createItem);

						auto refNode = Ptr(new WfReferenceExpression);
						refNode->name.value = variableName.ToString();

						auto assign = Ptr(new WfBinaryExpression);
						assign->op = WfBinaryOperator::Assign;
						assign->first = refNode;
						assign->second = createNode;

						auto stat = Ptr(new WfExpressionStatement);
						stat->expression = assign;
						return stat;
					}
					return nullptr;
				}

				Ptr<workflow::WfStatement> AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
				{
					auto block = Ptr(new WfBlockStatement);

					// TODO: (enumerable) foreach on group
					for (auto [prop, index] : indexed(arguments.Keys()))
					{
						if (prop == GlobalStringKey::Empty)
						{
							auto refNode = Ptr(new WfReferenceExpression);
							refNode->name.value = variableName.ToString();

							auto refChildren = Ptr(new WfMemberExpression);
							refChildren->parent = refNode;
							refChildren->name.value = L"Children";

							auto refAdd = Ptr(new WfMemberExpression);
							refAdd->parent = refChildren;
							refAdd->name.value = L"Add";

							auto call = Ptr(new WfCallExpression);
							call->function = refAdd;
							call->arguments.Add(arguments.GetByIndex(index)[0].expression);

							auto stat = Ptr(new WfExpressionStatement);
							stat->expression = call;
							block->statements.Add(stat);
						}
						else if (prop == _Tag)
						{
							{
								auto refNode = Ptr(new WfReferenceExpression);
								refNode->name.value = variableName.ToString();

								auto refData = Ptr(new WfMemberExpression);
								refData->parent = refNode;
								refData->name.value = L"Data";

								auto castExpr = Ptr(new WfTypeCastingExpression);
								castExpr->strategy = WfTypeCastingStrategy::Strong;
								castExpr->type = GetTypeFromTypeInfo(TypeInfoRetriver<Ptr<tree::TreeViewItem>>::CreateTypeInfo().Obj());
								castExpr->expression = refData;

								auto refProp = Ptr(new WfMemberExpression);
								refProp->parent = castExpr;
								refProp->name.value = L"tag";

								auto assign = Ptr(new WfBinaryExpression);
								assign->op = WfBinaryOperator::Assign;
								assign->first = refProp;
								assign->second = arguments.GetByIndex(index)[0].expression;

								auto stat = Ptr(new WfExpressionStatement);
								stat->expression = assign;
								block->statements.Add(stat);
							}

							if (prop != _Tag)
							{
								auto refNode = Ptr(new WfReferenceExpression);
								refNode->name.value = variableName.ToString();

								auto refNotifyDataModified = Ptr(new WfMemberExpression);
								refNotifyDataModified->parent = refNode;
								refNotifyDataModified->name.value = L"NotifyDataModified";

								auto call = Ptr(new WfCallExpression);
								call->function = refNotifyDataModified;

								auto stat = Ptr(new WfExpressionStatement);
								stat->expression = call;
								block->statements.Add(stat);
							}
						}
					}

					if (block->statements.Count() > 0)
					{
						return block;
					}
					return nullptr;
				}
			};

/***********************************************************************
Initialization
***********************************************************************/

			void LoadListControls(IGuiInstanceLoaderManager* manager)
			{
				manager->CreateVirtualType(
					GlobalStringKey::Get(description::TypeInfo<GuiComboBoxListControl>::content.typeName),
					Ptr(new GuiComboBoxInstanceLoader)
					);

				manager->SetLoader(Ptr(new GuiComboButtonInstanceLoader));
				manager->SetLoader(Ptr(new GuiTreeViewInstanceLoader));
				manager->SetLoader(Ptr(new GuiBindableTreeViewInstanceLoader));
				
				manager->CreateVirtualType(
					GlobalStringKey::Get(description::TypeInfo<tree::MemoryNodeProvider>::content.typeName),
					Ptr(new GuiTreeNodeInstanceLoader)
					);
			}
		}
	}
}

#endif


/***********************************************************************
.\INSTANCELOADERS\GUIINSTANCELOADER_PLUGIN.CPP
***********************************************************************/
/*
GuiInstanceLoader_Plugin.cpp
	GuiControl
		default: GuiControl*, GuiGraphicsComposition*
	GuiInstanceRootObject
		default: GuiComponent*
	GuiRawElement
GuiInstanceLoader_TemplateControl.h
	GuiControl
GuiInstanceLoader_Compositions.cpp
	GuiAxis
		ctor: AxisDirection
	GuiComposition
		default: GuiControl*, GuiGraphicsComposition*, Ptr<IGuiGraphicsElement>
	GuiTableComposition
		Rows, Columns: array(GuiCellOption)
	GuiCellComposition
		Site: SiteValue
GuiInstanceLoader_Document.cpp
	GuiDocumentItem
		default: GuiControl*, GuiGraphicsComposition*
	GuiDocumentViewer, GuiDocumentLable
		default: Ptr<GuiDocumentItem>
		ctor: Behavior(GuiDocumentConfig)
GuiInstanceLoader_List.cpp
	GuiComboBox
		ctor: ListControl(GuiListControl*)
	GuiTreeView
		Nodes: array(Ptr<tree::MemoryNodeProvider>)
	GuiBindableTreeView
		ctor: ReverseMappingProperty(WritableItemProperty<Value>)
	tree::TreeNode
		ctor: Text, Image
		Tag
GuiInstanceLoader_Templates.cpp
	GuiCommonDatePickerLook
		ctor: BackgroundColor, PrimaryTextColor, SecondaryTextColor
	GuiCommonScrollViewLook
		ctor: DefaultScrollSize
GuiInstanceLoader_Toolstrip.cpp
	GuiToolstripMenu, GuiToolstripMenuBar, GuiToolstripToolBar, GuiBindableRibbonGalleryMenu
		default: collection(GuiControl*)
	GuiToolstripButton
		SubMenu-set: GuiToolstripMenu*
	GuiRibbonButtons
		ctor: MaxSize, MinSize
*/


namespace vl
{
	namespace presentation
	{
		namespace instance_loaders
		{

#ifndef VCZH_DEBUG_NO_REFLECTION

/***********************************************************************
GuiControlInstanceLoader
***********************************************************************/

			class GuiControlInstanceLoader : public Object, public IGuiInstanceLoader
			{
			protected:
				GlobalStringKey					typeName;

			public:
				GuiControlInstanceLoader()
				{
					typeName = GlobalStringKey::Get(description::TypeInfo<GuiControl>::content.typeName);
				}

				GlobalStringKey GetTypeName()override
				{
					return typeName;
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					propertyNames.Add(GlobalStringKey::Empty);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == GlobalStringKey::Empty)
					{
						auto info = GuiInstancePropertyInfo::Collection(nullptr);
						info->acceptableTypes.Add(TypeInfoRetriver<GuiControl*>::CreateTypeInfo());
						info->acceptableTypes.Add(TypeInfoRetriver<GuiGraphicsComposition*>::CreateTypeInfo());
						if (propertyInfo.typeInfo.typeInfo->GetTypeDescriptor()->CanConvertTo(description::GetTypeDescriptor<GuiInstanceRootObject>()))
						{
							info->acceptableTypes.Add(TypeInfoRetriver<GuiComponent*>::CreateTypeInfo());
						}
						return info;
					}
					return IGuiInstanceLoader::GetPropertyType(precompileContext, propertyInfo);
				}

				Ptr<workflow::WfStatement> AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
				{
					auto block = Ptr(new WfBlockStatement);

					// TODO: (enumerable) foreach on group
					for (auto [prop, index] : indexed(arguments.Keys()))
					{
						const auto& values = arguments.GetByIndex(index);
						if (prop == GlobalStringKey::Empty)
						{
							auto value = values[0].expression;
							auto td = values[0].typeInfo->GetTypeDescriptor();

							Ptr<WfExpression> expr;
							if (td->CanConvertTo(description::GetTypeDescriptor<GuiComponent>()))
							{
								auto refControl = Ptr(new WfReferenceExpression);
								refControl->name.value = variableName.ToString();

								auto refAddComponent = Ptr(new WfMemberExpression);
								refAddComponent->parent = refControl;
								refAddComponent->name.value = L"AddComponent";

								auto call = Ptr(new WfCallExpression);
								call->function = refAddComponent;
								call->arguments.Add(value);

								expr = call;
							}
							else if (td->CanConvertTo(description::GetTypeDescriptor<GuiControlHost>()))
							{
								auto refControl = Ptr(new WfReferenceExpression);
								refControl->name.value = variableName.ToString();

								auto refAddControlHostComponent = Ptr(new WfMemberExpression);
								refAddControlHostComponent->parent = refControl;
								refAddControlHostComponent->name.value = L"AddControlHostComponent";

								auto call = Ptr(new WfCallExpression);
								call->function = refAddControlHostComponent;
								call->arguments.Add(value);

								expr = call;
							}
							else if (td->CanConvertTo(description::GetTypeDescriptor<GuiControl>()))
							{
								auto refControl = Ptr(new WfReferenceExpression);
								refControl->name.value = variableName.ToString();

								auto refAddChild = Ptr(new WfMemberExpression);
								refAddChild->parent = refControl;
								refAddChild->name.value = L"AddChild";

								auto call = Ptr(new WfCallExpression);
								call->function = refAddChild;
								call->arguments.Add(value);

								expr = call;
							}
							else if (td->CanConvertTo(description::GetTypeDescriptor<GuiGraphicsComposition>()))
							{
								auto refControl = Ptr(new WfReferenceExpression);
								refControl->name.value = variableName.ToString();

								auto refContainerComposition = Ptr(new WfMemberExpression);
								refContainerComposition->parent = refControl;
								refContainerComposition->name.value = L"ContainerComposition";

								auto refAddChild = Ptr(new WfMemberExpression);
								refAddChild->parent = refContainerComposition;
								refAddChild->name.value = L"AddChild";

								auto call = Ptr(new WfCallExpression);
								call->function = refAddChild;
								call->arguments.Add(value);

								expr = call;
							}

							if (expr)
							{
								auto stat = Ptr(new WfExpressionStatement);
								stat->expression = expr;
								block->statements.Add(stat);
							}
						}
					}

					if (block->statements.Count() > 0)
					{
						return block;
					}
					return nullptr;
				}
			};

/***********************************************************************
GuiRawElementInstanceLoader
***********************************************************************/

			class GuiRawElementInstanceLoader : public Object, public IGuiInstanceLoader
			{
			protected:
				GlobalStringKey							typeName;

			public:
				GuiRawElementInstanceLoader()
				{
					typeName = GlobalStringKey::Get(L"presentation::elements::GuiRawElement");
				}

				GlobalStringKey GetTypeName()override
				{
					return typeName;
				}

				bool CanCreate(const TypeInfo& typeInfo) override
				{
					return typeName == typeInfo.typeName;
				}

				Ptr<workflow::WfStatement> CreateInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)override
				{
					if (CanCreate(typeInfo))
					{
						auto refCreateRawElement = Ptr(new WfChildExpression);
						refCreateRawElement->parent = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<IGuiGraphicsElement>());
						refCreateRawElement->name.value = L"CreateRawElement";

						auto call = Ptr(new WfCallExpression);
						call->function = refCreateRawElement;

						auto refVariable = Ptr(new WfReferenceExpression);
						refVariable->name.value = variableName.ToString();

						auto assign = Ptr(new WfBinaryExpression);
						assign->op = WfBinaryOperator::Assign;
						assign->first = refVariable;
						assign->second = call;

						auto stat = Ptr(new WfExpressionStatement);
						stat->expression = assign;
						return stat;
					}
					return nullptr;
				}
			};

#endif
			
/***********************************************************************
GuiPredefinedInstanceLoadersPlugin
***********************************************************************/

			void InitializeTrackerProgressBar(const WString& variableName, Ptr<WfBlockStatement> block)
			{
				auto refVariable = Ptr(new WfReferenceExpression);
				refVariable->name.value = variableName;

				auto refSetPageSize = Ptr(new WfMemberExpression);
				refSetPageSize->parent = refVariable;
				refSetPageSize->name.value = L"SetPageSize";

				auto refZero = Ptr(new WfIntegerExpression);
				refZero->value.value = L"0";

				auto call = Ptr(new WfCallExpression);
				call->function = refSetPageSize;
				call->arguments.Add(refZero);

				auto stat = Ptr(new WfExpressionStatement);
				stat->expression = call;
				block->statements.Add(stat);
			}

			extern void LoadToolstripControls(IGuiInstanceLoaderManager* manager);
			extern void LoadListControls(IGuiInstanceLoaderManager* manager);
			extern void LoadDocumentControls(IGuiInstanceLoaderManager* manager);
			extern void LoadCompositions(IGuiInstanceLoaderManager* manager);
			extern void LoadTemplates(IGuiInstanceLoaderManager* manager);

			class GuiPredefinedInstanceLoadersPlugin : public Object, public IGuiPlugin
			{
			public:

				GUI_PLUGIN_NAME(GacUI_Instance_TypeLoaders)
				{
					GUI_PLUGIN_DEPEND(GacUI_Res_ResourceResolver);
					GUI_PLUGIN_DEPEND(GacUI_Instance);
					GUI_PLUGIN_DEPEND(GacUI_Instance_Reflection);
				}

				void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
				{
#ifndef VCZH_DEBUG_NO_REFLECTION
					if (controllerUnrelatedPlugins)
					{
						IGuiInstanceLoaderManager* manager=GetInstanceLoaderManager();

#define ADD_TEMPLATE_CONTROL(TYPENAME, THEME_NAME)\
						manager->SetLoader(\
							Ptr(new GuiTemplateControlInstanceLoader<TYPENAME>(\
								L"presentation::controls::" L ## #TYPENAME,\
								theme::ThemeName::THEME_NAME\
								)\
							))

#define ADD_VIRTUAL_CONTROL(VIRTUALTYPENAME, TYPENAME, THEME_NAME)\
						manager->CreateVirtualType(GlobalStringKey::Get(description::TypeInfo<TYPENAME>::content.typeName),\
							Ptr(new GuiTemplateControlInstanceLoader<TYPENAME>(\
								L"presentation::controls::Gui" L ## #VIRTUALTYPENAME,\
								theme::ThemeName::THEME_NAME\
								)\
							))

#define ADD_VIRTUAL_CONTROL_F(VIRTUALTYPENAME, TYPENAME, THEME_NAME, INIT_FUNCTION)\
						manager->CreateVirtualType(GlobalStringKey::Get(description::TypeInfo<TYPENAME>::content.typeName),\
							Ptr(new GuiTemplateControlInstanceLoader<TYPENAME>(\
								L"presentation::controls::Gui" L ## #VIRTUALTYPENAME,\
								theme::ThemeName::THEME_NAME,\
								nullptr,\
								INIT_FUNCTION\
								)\
							))

						manager->CreateVirtualType(
							GlobalStringKey::Get(description::TypeInfo<IGuiGraphicsElement>::content.typeName),
							Ptr(new GuiRawElementInstanceLoader)
							);

						manager->SetLoader(Ptr(new GuiControlInstanceLoader));

						/*													REAL-CONTROL-TYPE				THEME-NAME											*/
						ADD_TEMPLATE_CONTROL	(							GuiCustomControl,				CustomControl										);
						ADD_TEMPLATE_CONTROL	(							GuiLabel,						Label												);
						ADD_TEMPLATE_CONTROL	(							GuiButton,						Button												);
						ADD_TEMPLATE_CONTROL	(							GuiTabPage,						CustomControl										);
						ADD_TEMPLATE_CONTROL	(							GuiTab,							Tab													);
						ADD_TEMPLATE_CONTROL	(							GuiScrollContainer,				ScrollView											);
						ADD_TEMPLATE_CONTROL	(							GuiWindow,						Window												);
						ADD_TEMPLATE_CONTROL	(							GuiTextList,					TextList											);
						ADD_TEMPLATE_CONTROL	(							GuiBindableTextList,			TextList											);
						ADD_TEMPLATE_CONTROL	(							GuiListView,					ListView											);
						ADD_TEMPLATE_CONTROL	(							GuiBindableListView,			ListView											);
						ADD_TEMPLATE_CONTROL	(							GuiBindableDataGrid,			ListView											);
						ADD_TEMPLATE_CONTROL	(							GuiMultilineTextBox,			MultilineTextBox									);
						ADD_TEMPLATE_CONTROL	(							GuiSinglelineTextBox,			SinglelineTextBox									);
						ADD_TEMPLATE_CONTROL	(							GuiDatePicker,					DatePicker											);
						ADD_TEMPLATE_CONTROL	(							GuiDateComboBox,				DateComboBox										);
						ADD_TEMPLATE_CONTROL	(							GuiRibbonTab,					RibbonTab											);
						ADD_TEMPLATE_CONTROL	(							GuiRibbonTabPage,				CustomControl										);
						ADD_TEMPLATE_CONTROL	(							GuiRibbonGroup,					RibbonGroup											);
						ADD_TEMPLATE_CONTROL	(							GuiRibbonIconLabel,				RibbonIconLabel										);
						ADD_TEMPLATE_CONTROL	(							GuiRibbonToolstrips,			RibbonToolstrips									);
						ADD_TEMPLATE_CONTROL	(							GuiRibbonGallery,				RibbonGallery										);
						ADD_TEMPLATE_CONTROL	(							GuiBindableRibbonGalleryList,	RibbonGalleryList									);

						/*						VIRTUAL-CONTROL-TYPE		REAL-CONTROL-TYPE				THEME-NAME											*/
						ADD_VIRTUAL_CONTROL		(GroupBox,					GuiControl,						GroupBox											);
						ADD_VIRTUAL_CONTROL		(MenuSplitter,				GuiControl,						MenuSplitter										);
						ADD_VIRTUAL_CONTROL		(MenuBarButton,				GuiToolstripButton,				MenuBarButton										);
						ADD_VIRTUAL_CONTROL		(MenuItemButton,			GuiToolstripButton,				MenuItemButton										);
						ADD_VIRTUAL_CONTROL		(ToolstripToolBarInMenu,	GuiToolstripToolBar,			ToolstripToolBarInMenu								);
						ADD_VIRTUAL_CONTROL		(ToolstripDropdownButton,	GuiToolstripButton,				ToolstripDropdownButton								);
						ADD_VIRTUAL_CONTROL		(ToolstripSplitButton,		GuiToolstripButton,				ToolstripSplitButton								);
						ADD_VIRTUAL_CONTROL		(ToolstripSplitter,			GuiControl,						ToolstripSplitter									);
						ADD_VIRTUAL_CONTROL		(ToolstripSplitterInMenu,	GuiControl,						ToolstripSplitterInMenu								);
						ADD_VIRTUAL_CONTROL		(RibbonSmallButton,			GuiToolstripButton,				RibbonSmallButton									);
						ADD_VIRTUAL_CONTROL		(RibbonSmallDropdownButton,	GuiToolstripButton,				RibbonSmallDropdownButton							);
						ADD_VIRTUAL_CONTROL		(RibbonSmallSplitButton,	GuiToolstripButton,				RibbonSmallSplitButton								);
						ADD_VIRTUAL_CONTROL		(RibbonLargeButton,			GuiToolstripButton,				RibbonLargeButton									);
						ADD_VIRTUAL_CONTROL		(RibbonLargeDropdownButton,	GuiToolstripButton,				RibbonLargeDropdownButton							);
						ADD_VIRTUAL_CONTROL		(RibbonLargeSplitButton,	GuiToolstripButton,				RibbonLargeSplitButton								);
						ADD_VIRTUAL_CONTROL		(RibbonSmallIconLabel,		GuiRibbonIconLabel,				RibbonSmallIconLabel								);
						ADD_VIRTUAL_CONTROL		(RibbonSplitter,			GuiControl,						RibbonSplitter										);
						ADD_VIRTUAL_CONTROL		(RibbonToolstripHeader,		GuiControl,						RibbonToolstripHeader								);
						ADD_VIRTUAL_CONTROL		(CheckBox,					GuiSelectableButton,			CheckBox											);
						ADD_VIRTUAL_CONTROL		(RadioButton,				GuiSelectableButton,			RadioButton											);
						ADD_VIRTUAL_CONTROL		(HScroll,					GuiScroll,						HScroll												);
						ADD_VIRTUAL_CONTROL		(VScroll,					GuiScroll,						VScroll												);
						ADD_VIRTUAL_CONTROL_F	(HTracker,					GuiScroll,						HTracker,				InitializeTrackerProgressBar);
						ADD_VIRTUAL_CONTROL_F	(VTracker,					GuiScroll,						VTracker,				InitializeTrackerProgressBar);
						ADD_VIRTUAL_CONTROL_F	(ProgressBar,				GuiScroll,						ProgressBar,			InitializeTrackerProgressBar);

						LoadToolstripControls(manager);
						LoadListControls(manager);
						LoadDocumentControls(manager);
						LoadCompositions(manager);
						LoadTemplates(manager);
					}
#undef ADD_TEMPLATE_CONTROL
#undef ADD_VIRTUAL_CONTROL
#undef ADD_VIRTUAL_CONTROL_F
#endif
				}

				void Unload(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
				{
				}
			};
			GUI_REGISTER_PLUGIN(GuiPredefinedInstanceLoadersPlugin)
		}
	}
}

/***********************************************************************
.\INSTANCELOADERS\GUIINSTANCELOADER_TEMPLATES.CPP
***********************************************************************/

#ifndef VCZH_DEBUG_NO_REFLECTION

namespace vl
{
	namespace presentation
	{
		namespace instance_loaders
		{

/***********************************************************************
GuiCommonDatePickerLookLoader
***********************************************************************/

			class GuiCommonDatePickerLookLoader : public Object, public IGuiInstanceLoader
			{
			protected:
				GlobalStringKey					typeName;
				GlobalStringKey					_BackgroundColor;
				GlobalStringKey					_PrimaryTextColor;
				GlobalStringKey					_SecondaryTextColor;

			public:
				GuiCommonDatePickerLookLoader()
				{
					typeName = GlobalStringKey::Get(description::TypeInfo<GuiCommonDatePickerLook>::content.typeName);
					_BackgroundColor = GlobalStringKey::Get(L"BackgroundColor");
					_PrimaryTextColor = GlobalStringKey::Get(L"PrimaryTextColor");
					_SecondaryTextColor = GlobalStringKey::Get(L"SecondaryTextColor");
				}

				GlobalStringKey GetTypeName()override
				{
					return typeName;
				}

				void GetRequiredPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					if (CanCreate(typeInfo))
					{
						propertyNames.Add(_BackgroundColor);
						propertyNames.Add(_PrimaryTextColor);
						propertyNames.Add(_SecondaryTextColor);
					}
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					GetRequiredPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _BackgroundColor || propertyInfo.propertyName == _PrimaryTextColor || propertyInfo.propertyName == _SecondaryTextColor)
					{
						auto info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<Color>::CreateTypeInfo());
						info->usage = GuiInstancePropertyInfo::ConstructorArgument;
						return info;
					}
					return IGuiInstanceLoader::GetPropertyType(precompileContext, propertyInfo);
				}

				bool CanCreate(const TypeInfo& typeInfo)override
				{
					return typeInfo.typeName == typeName;
				}

				Ptr<workflow::WfStatement> CreateInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)override
				{
					if (CanCreate(typeInfo))
					{
						vint indexBackgroundColor = arguments.Keys().IndexOf(_BackgroundColor);
						vint indexPrimaryTextColor = arguments.Keys().IndexOf(_PrimaryTextColor);
						vint indexSecondaryTextColor = arguments.Keys().IndexOf(_SecondaryTextColor);
						if (indexBackgroundColor != -1 && indexPrimaryTextColor != -1 && indexSecondaryTextColor != -1)
						{
							auto type = TypeInfoRetriver<GuiCommonDatePickerLook*>::CreateTypeInfo();
							auto createExpr = Ptr(new WfNewClassExpression);
							createExpr->type = GetTypeFromTypeInfo(type.Obj());
							createExpr->arguments.Add(arguments.GetByIndex(indexBackgroundColor)[0].expression);
							createExpr->arguments.Add(arguments.GetByIndex(indexPrimaryTextColor)[0].expression);
							createExpr->arguments.Add(arguments.GetByIndex(indexSecondaryTextColor)[0].expression);

							auto refVariable = Ptr(new WfReferenceExpression);
							refVariable->name.value = variableName.ToString();

							auto assignExpr = Ptr(new WfBinaryExpression);
							assignExpr->op = WfBinaryOperator::Assign;
							assignExpr->first = refVariable;
							assignExpr->second = createExpr;

							auto assignStat = Ptr(new WfExpressionStatement);
							assignStat->expression = assignExpr;
							return assignStat;
						}
					}
					return nullptr;
				}
			};

/***********************************************************************
GuiCommonScrollViewLookLoader
***********************************************************************/

			class GuiCommonScrollViewLookLoader : public Object, public IGuiInstanceLoader
			{
			protected:
				GlobalStringKey					typeName;
				GlobalStringKey					_DefaultScrollSize;

			public:
				GuiCommonScrollViewLookLoader()
				{
					typeName = GlobalStringKey::Get(description::TypeInfo<GuiCommonScrollViewLook>::content.typeName);
					_DefaultScrollSize = GlobalStringKey::Get(L"DefaultScrollSize");
				}

				GlobalStringKey GetTypeName()override
				{
					return typeName;
				}

				void GetRequiredPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					if (CanCreate(typeInfo))
					{
						propertyNames.Add(_DefaultScrollSize);
					}
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					GetRequiredPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _DefaultScrollSize)
					{
						Ptr<GuiInstancePropertyInfo> info;
						switch (precompileContext.targetCpuArchitecture)
						{
						case GuiResourceCpuArchitecture::x86:
							info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<vint32_t>::CreateTypeInfo());
							break;
						case GuiResourceCpuArchitecture::x64:
							info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<vint64_t>::CreateTypeInfo());
							break;
						default:
							CHECK_FAIL(L"The target CPU architecture is unspecified.");
						}
						info->usage = GuiInstancePropertyInfo::ConstructorArgument;
						return info;
					}
					return IGuiInstanceLoader::GetPropertyType(precompileContext, propertyInfo);
				}

				bool CanCreate(const TypeInfo& typeInfo)override
				{
					return typeInfo.typeName == typeName;
				}

				Ptr<workflow::WfStatement> CreateInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)override
				{
					if (CanCreate(typeInfo))
					{
						vint indexDefaultScrollSize = arguments.Keys().IndexOf(_DefaultScrollSize);
						if (indexDefaultScrollSize != -1)
						{
							auto type = TypeInfoRetriver<GuiCommonScrollViewLook*>::CreateTypeInfo();
							auto createExpr = Ptr(new WfNewClassExpression);
							createExpr->type = GetTypeFromTypeInfo(type.Obj());
							createExpr->arguments.Add(arguments.GetByIndex(indexDefaultScrollSize)[0].expression);

							auto refVariable = Ptr(new WfReferenceExpression);
							refVariable->name.value = variableName.ToString();

							auto assignExpr = Ptr(new WfBinaryExpression);
							assignExpr->op = WfBinaryOperator::Assign;
							assignExpr->first = refVariable;
							assignExpr->second = createExpr;

							auto assignStat = Ptr(new WfExpressionStatement);
							assignStat->expression = assignExpr;
							return assignStat;
						}
					}
					return nullptr;
				}
			};

/***********************************************************************
Initialization
***********************************************************************/

			void LoadTemplates(IGuiInstanceLoaderManager* manager)
			{
				manager->SetLoader(Ptr(new GuiCommonDatePickerLookLoader));
				manager->SetLoader(Ptr(new GuiCommonScrollViewLookLoader));
			}
		}
	}
}

#endif


/***********************************************************************
.\INSTANCELOADERS\GUIINSTANCELOADER_TOOLSTRIP.CPP
***********************************************************************/

#ifndef VCZH_DEBUG_NO_REFLECTION

namespace vl
{
	namespace presentation
	{
		namespace instance_loaders
		{
			Ptr<workflow::WfStatement> AddControlToToolstrip(GlobalStringKey variableName, IGuiInstanceLoader::ArgumentMap& arguments, GuiResourceError::List& errors)
			{
				auto block = Ptr(new WfBlockStatement);

				// TODO: (enumerable) foreach on group
				for (auto [prop, index] : indexed(arguments.Keys()))
				{
					const auto& values = arguments.GetByIndex(index);
					if (prop == GlobalStringKey::Empty)
					{
						auto value = values[0].expression;
						auto td = values[0].typeInfo->GetTypeDescriptor();

						Ptr<WfExpression> expr;
						if (td->CanConvertTo(description::GetTypeDescriptor<GuiControl>()))
						{
							auto refControl = Ptr(new WfReferenceExpression);
							refControl->name.value = variableName.ToString();

							auto refToolstripItems = Ptr(new WfMemberExpression);
							refToolstripItems->parent = refControl;
							refToolstripItems->name.value = L"ToolstripItems";

							auto refAdd = Ptr(new WfMemberExpression);
							refAdd->parent = refToolstripItems;
							refAdd->name.value = L"Add";

							auto call = Ptr(new WfCallExpression);
							call->function = refAdd;
							call->arguments.Add(value);

							expr = call;
						}

						if (expr)
						{
							auto stat = Ptr(new WfExpressionStatement);
							stat->expression = expr;
							block->statements.Add(stat);
						}
					}
				}

				if (block->statements.Count() > 0)
				{
					return block;
				}
				return nullptr;
			}

/***********************************************************************
GuiToolstripInstanceLoaderBase
***********************************************************************/

			template<typename TBaseType>
			class GuiToolstripInstanceLoaderBase : public TBaseType
			{
			private:
				using TypeInfo = typename TBaseType::TypeInfo;

			public:
				using ArgumentMap = IGuiInstanceLoader::ArgumentMap;
				using PropertyInfo = IGuiInstanceLoader::PropertyInfo;

				GuiToolstripInstanceLoaderBase(const WString& _typeName, theme::ThemeName themeName, Ptr<WfExpression>(*_argumentFunction)(ArgumentMap&))
					:TBaseType(_typeName, themeName, _argumentFunction)
				{
				}

				GuiToolstripInstanceLoaderBase(const WString& _typeName, theme::ThemeName themeName)
					:TBaseType(_typeName, themeName)
				{
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					propertyNames.Add(GlobalStringKey::Empty);
					TBaseType::GetPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == GlobalStringKey::Empty)
					{
						return GuiInstancePropertyInfo::CollectionWithParent(TypeInfoRetriver<GuiControl*>::CreateTypeInfo());
					}
					return TBaseType::GetPropertyType(precompileContext, propertyInfo);
				}

				Ptr<workflow::WfStatement> AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
				{
					if (auto statement = AddControlToToolstrip(variableName, arguments, errors))
					{
						return statement;
					}
					else
					{
						return TBaseType::AssignParameters(precompileContext, resolvingResult, typeInfo, variableName, arguments, attPosition, errors);
					}
				}
			};

/***********************************************************************
GuiToolstripMenuInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiToolstripMenu>
			class GuiToolstripMenuInstanceLoader : public GuiToolstripInstanceLoaderBase<BASE_TYPE>
			{
			public:
				static Ptr<WfExpression> ArgumentFunction(ArgumentMap&)
				{
					auto expr = Ptr(new WfLiteralExpression);
					expr->value = WfLiteralValue::Null;
					return expr;
				}
			public:
				GuiToolstripMenuInstanceLoader()
					:GuiToolstripInstanceLoaderBase<BASE_TYPE>(description::TypeInfo<GuiToolstripMenu>::content.typeName, theme::ThemeName::Menu, ArgumentFunction)
				{
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiToolstripMenuBarInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiToolstripMenuBar>
			class GuiToolstripMenuBarInstanceLoader : public GuiToolstripInstanceLoaderBase<BASE_TYPE>
			{
			public:
				GuiToolstripMenuBarInstanceLoader()
					:GuiToolstripInstanceLoaderBase<BASE_TYPE>(description::TypeInfo<GuiToolstripMenuBar>::content.typeName, theme::ThemeName::MenuBar)
				{
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiToolstripToolBarInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiToolstripToolBar>
			class GuiToolstripToolBarInstanceLoader : public GuiToolstripInstanceLoaderBase<BASE_TYPE>
			{
			public:
				GuiToolstripToolBarInstanceLoader()
					:GuiToolstripInstanceLoaderBase<BASE_TYPE>(description::TypeInfo<GuiToolstripToolBar>::content.typeName, theme::ThemeName::ToolstripToolBar)
				{
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiToolstripGroupContainerInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiToolstripGroupContainer>
			class GuiToolstripGroupContainerInstanceLoader : public GuiToolstripInstanceLoaderBase<BASE_TYPE>
			{
			public:
				GuiToolstripGroupContainerInstanceLoader()
					:GuiToolstripInstanceLoaderBase<BASE_TYPE>(description::TypeInfo<GuiToolstripGroupContainer>::content.typeName, theme::ThemeName::CustomControl)
				{
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiToolstripGroupInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiToolstripGroup>
			class GuiToolstripGroupInstanceLoader : public GuiToolstripInstanceLoaderBase<BASE_TYPE>
			{
			public:
				GuiToolstripGroupInstanceLoader()
					:GuiToolstripInstanceLoaderBase<BASE_TYPE>(description::TypeInfo<GuiToolstripGroup>::content.typeName, theme::ThemeName::CustomControl)
				{
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiToolstripButtonInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiToolstripButton>
			class GuiToolstripButtonInstanceLoader : public BASE_TYPE
			{
			protected:
				GlobalStringKey					_SubMenu;

			public:
				GuiToolstripButtonInstanceLoader()
					:BASE_TYPE(description::TypeInfo<GuiToolstripButton>::content.typeName, theme::ThemeName::ToolstripButton)
				{
					_SubMenu = GlobalStringKey::Get(L"SubMenu");
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					propertyNames.Add(_SubMenu);
					BASE_TYPE::GetPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _SubMenu)
					{
						return GuiInstancePropertyInfo::Set(TypeInfoRetriver<GuiToolstripMenu*>::CreateTypeInfo());
					}
					return BASE_TYPE::GetPropertyType(precompileContext, propertyInfo);
				}

				Ptr<workflow::WfExpression> GetParameter(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const PropertyInfo& propertyInfo, GlobalStringKey variableName, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override
				{
					if (propertyInfo.propertyName == _SubMenu)
					{
						auto refControl = Ptr(new WfReferenceExpression);
						refControl->name.value = variableName.ToString();

						auto refEnsureToolstripSubMenu = Ptr(new WfMemberExpression);
						refEnsureToolstripSubMenu->parent = refControl;
						refEnsureToolstripSubMenu->name.value = L"EnsureToolstripSubMenu";

						auto call = Ptr(new WfCallExpression);
						call->function = refEnsureToolstripSubMenu;

						return call;
					}
					return BASE_TYPE::GetParameter(precompileContext, resolvingResult, propertyInfo, variableName, attPosition, errors);
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiRibbonToolstripMenuInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiRibbonToolstripMenu>
			class GuiRibbonToolstripMenuInstanceLoader : public GuiToolstripInstanceLoaderBase<BASE_TYPE>
			{
			public:
				static Ptr<WfExpression> ArgumentFunction(ArgumentMap&)
				{
					auto expr = Ptr(new WfLiteralExpression);
					expr->value = WfLiteralValue::Null;
					return expr;
				}
			public:
				GuiRibbonToolstripMenuInstanceLoader()
					:GuiToolstripInstanceLoaderBase<BASE_TYPE>(description::TypeInfo<GuiRibbonToolstripMenu>::content.typeName, theme::ThemeName::RibbonToolstripMenu, ArgumentFunction)
				{
				}
			};
#undef BASE_TYPE

/***********************************************************************
GuiRibbonButtonsInstanceLoader
***********************************************************************/

#define BASE_TYPE GuiTemplateControlInstanceLoader<GuiRibbonButtons>
			class GuiRibbonButtonsInstanceLoader : public BASE_TYPE
			{
			protected:
				GlobalStringKey					_MaxSize;
				GlobalStringKey					_MinSize;

				void AddAdditionalArguments(types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceError::List& errors, Ptr<WfNewClassExpression> createControl)override
				{
					vint indexMaxSize = arguments.Keys().IndexOf(_MaxSize);
					vint indexMinSize = arguments.Keys().IndexOf(_MinSize);
					if (indexMaxSize != -1 && indexMinSize != -1)
					{
						createControl->arguments.Add(arguments.GetByIndex(indexMaxSize)[0].expression);
						createControl->arguments.Add(arguments.GetByIndex(indexMinSize)[0].expression);
					}
				}
			public:
				GuiRibbonButtonsInstanceLoader()
					:BASE_TYPE(description::TypeInfo<GuiRibbonButtons>::content.typeName, theme::ThemeName::RibbonButtons)
				{
					_MaxSize = GlobalStringKey::Get(L"MaxSize");
					_MinSize = GlobalStringKey::Get(L"MinSize");
				}

				void GetRequiredPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					if (CanCreate(typeInfo))
					{
						propertyNames.Add(_MaxSize);
						propertyNames.Add(_MinSize);
					}
				}

				void GetPropertyNames(GuiResourcePrecompileContext& precompileContext, const TypeInfo& typeInfo, collections::List<GlobalStringKey>& propertyNames)override
				{
					GetRequiredPropertyNames(precompileContext, typeInfo, propertyNames);
				}

				Ptr<GuiInstancePropertyInfo> GetPropertyType(GuiResourcePrecompileContext& precompileContext, const PropertyInfo& propertyInfo)override
				{
					if (propertyInfo.propertyName == _MaxSize || propertyInfo.propertyName == _MinSize)
					{
						auto info = GuiInstancePropertyInfo::Assign(TypeInfoRetriver<RibbonButtonSize>::CreateTypeInfo());
						info->usage = GuiInstancePropertyInfo::ConstructorArgument;
						return info;
					}
					return IGuiInstanceLoader::GetPropertyType(precompileContext, propertyInfo);
				}
			};
#undef BASE_TYPE

/***********************************************************************
Initialization
***********************************************************************/

			void LoadToolstripControls(IGuiInstanceLoaderManager* manager)
			{
				manager->SetLoader(Ptr(new GuiToolstripMenuInstanceLoader));
				manager->SetLoader(Ptr(new GuiToolstripMenuBarInstanceLoader));
				manager->SetLoader(Ptr(new GuiToolstripToolBarInstanceLoader));
				manager->SetLoader(Ptr(new GuiToolstripGroupContainerInstanceLoader));
				manager->SetLoader(Ptr(new GuiToolstripGroupInstanceLoader));
				manager->SetLoader(Ptr(new GuiToolstripButtonInstanceLoader));
				manager->SetLoader(Ptr(new GuiRibbonButtonsInstanceLoader));
				manager->SetLoader(Ptr(new GuiRibbonToolstripMenuInstanceLoader));
			}
		}
	}
}

#endif


/***********************************************************************
.\INSTANCEQUERY\GUIINSTANCEQUERY.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace instancequery;

/***********************************************************************
ExecuteQueryVisitor
***********************************************************************/

		class ExecuteQueryVisitor : public Object, public GuiIqQuery::IVisitor
		{
		public:
			Ptr<GuiInstanceContext>				context;
			List<Ptr<GuiConstructorRepr>>&		input;
			List<Ptr<GuiConstructorRepr>>&		output;

			ExecuteQueryVisitor(Ptr<GuiInstanceContext> _context, List<Ptr<GuiConstructorRepr>>& _input, List<Ptr<GuiConstructorRepr>>& _output)
				:context(_context), input(_input), output(_output)
			{
			}

			static bool TestCtor(GuiIqPrimaryQuery* node, GlobalStringKey attribute, Ptr<GuiConstructorRepr> ctor)
			{
				if (node->attributeNameOption == GuiIqNameOption::Specified && node->attributeName.value != attribute.ToString())
				{
					return false;
				}
				if (node->typeNameOption == GuiIqNameOption::Specified && node->typeName.value != ctor->typeName.ToString())
				{
					return false;
				}
				if (node->referenceName.value != L"")
				{
					bool instanceName = ctor->instanceName != GlobalStringKey::Empty && node->referenceName.value == ctor->instanceName.ToString();
					bool styleName = ctor->styleName && node->referenceName.value == ctor->styleName.Value();
					return instanceName || styleName;
				}
				return true;
			}

			void Traverse(GuiIqPrimaryQuery* node, Ptr<GuiAttSetterRepr> setter)
			{
				if (setter)
				{
					// TODO: (enumerable) foreach on group
					for (auto [attribute, index] : indexed(setter->setters.Keys()))
					{
						auto setterValue = setter->setters.Values()[index];
						for (auto value : setterValue->values)
						{
							if (auto ctor = value.Cast<GuiConstructorRepr>())
							{
								if (TestCtor(node, attribute, ctor))
								{
									output.Add(ctor);
								}
							}
							if (node->childOption == GuiIqChildOption::Indirect)
							{
								if (auto setter = value.Cast<GuiAttSetterRepr>())
								{
									Traverse(node, setter);
								}
							}
						}
					}
				}
				else
				{
					if (TestCtor(node, GlobalStringKey::Empty, context->instance))
					{
						output.Add(context->instance);
					}
					if (node->childOption == GuiIqChildOption::Indirect)
					{
						Traverse(node, context->instance);
					}
				}
			}

			void Visit(GuiIqPrimaryQuery* node)override
			{
				auto inputExists = &input;
				if (inputExists)
				{
					for (auto setter : input)
					{
						Traverse(node, setter);
					}
				}
				else
				{
					Traverse(node, 0);
				}
			}

			void Visit(GuiIqCascadeQuery* node)override
			{
				List<Ptr<GuiConstructorRepr>> temp;
				ExecuteQuery(node->parent, context, input, temp);
				ExecuteQuery(node->child, context, temp, output);
			}

			void Visit(GuiIqSetQuery* node)override
			{
				List<Ptr<GuiConstructorRepr>> first, second;
				ExecuteQuery(node->first, context, input, first);
				ExecuteQuery(node->second, context, input, second);

				switch (node->op)
				{
				case GuiIqBinaryOperator::ExclusiveOr:
					CopyFrom(output, From(first).Except(second).Union(From(second).Except(second)));
					break;
				case GuiIqBinaryOperator::Intersect:
					CopyFrom(output, From(first).Intersect(second));
					break;
				case GuiIqBinaryOperator::Union:
					CopyFrom(output, From(first).Union(second));
					break;
				case GuiIqBinaryOperator::Substract:
					CopyFrom(output, From(first).Except(second));
					break;
				default:;
				}
			}
		};

/***********************************************************************
ExecuteQuery
***********************************************************************/

		void ExecuteQuery(Ptr<GuiIqQuery> query, Ptr<GuiInstanceContext> context, collections::List<Ptr<GuiConstructorRepr>>& input, collections::List<Ptr<GuiConstructorRepr>>& output)
		{
			ExecuteQueryVisitor visitor(context, input, output);
			query->Accept(&visitor);
		}

		void ExecuteQuery(Ptr<GuiIqQuery> query, Ptr<GuiInstanceContext> context, collections::List<Ptr<GuiConstructorRepr>>& output)
		{
#if defined(VCZH_GCC) && defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnull-dereference"
#endif
			ExecuteQuery(query, context, *(List<Ptr<GuiConstructorRepr>>*)0, output);
#if defined(VCZH_GCC) && defined(__clang__)
#pragma clang diagnostic pop
#endif
		}

/***********************************************************************
ApplyStyle
***********************************************************************/

		void ApplyStyleInternal(Ptr<GuiAttSetterRepr> src, Ptr<GuiAttSetterRepr> dst)
		{
			// TODO: (enumerable) foreach on dictionary
			for (auto [attribute, srcIndex] : indexed(src->setters.Keys()))
			{
				auto srcValue = src->setters.Values()[srcIndex];
				vint dstIndex = dst->setters.Keys().IndexOf(attribute);
				if (dstIndex == -1)
				{
					dst->setters.Add(attribute, srcValue);
				}
				else
				{
					auto dstValue = dst->setters.Values()[dstIndex];
					if (srcValue->binding == dstValue->binding)
					{
						if (srcValue->binding == GlobalStringKey::_Set)
						{
							ApplyStyleInternal(srcValue->values[0].Cast<GuiAttSetterRepr>(), dstValue->values[0].Cast<GuiAttSetterRepr>());
						}
						else
						{
							CopyFrom(dstValue->values, srcValue->values, true);
						}
					}
				}
			}

			// TODO: (enumerable) foreach
			for (auto [eventName, srcIndex] : indexed(src->eventHandlers.Keys()))
			{
				if (!dst->eventHandlers.Keys().Contains(eventName))
				{
					auto srcValue = src->eventHandlers.Values()[srcIndex];
					dst->eventHandlers.Add(eventName, srcValue);
				}
			}

			// TODO: (enumerable) foreach
			for (auto [varName, srcIndex] : indexed(src->environmentVariables.Keys()))
			{
				if (!dst->environmentVariables.Keys().Contains(varName))
				{
					auto srcValue = src->environmentVariables.Values()[srcIndex];
					dst->environmentVariables.Add(varName, srcValue);
				}
			}
		}

		void ApplyStyle(Ptr<GuiInstanceStyle> style, Ptr<GuiConstructorRepr> ctor)
		{
			ApplyStyleInternal(style->setter->Clone().Cast<GuiAttSetterRepr>(), ctor);
		}

/***********************************************************************
GuiIqPrint
***********************************************************************/

		class GuiIqPrintVisitor : public Object, public GuiIqQuery::IVisitor
		{
		public:
			stream::StreamWriter&				writer;

			GuiIqPrintVisitor(stream::StreamWriter& _writer)
				:writer(_writer)
			{
			}

			void Visit(GuiIqPrimaryQuery* node)override
			{
				switch (node->childOption)
				{
				case GuiIqChildOption::Direct:
					writer.WriteString(L"/");
					break;
				case GuiIqChildOption::Indirect:
					writer.WriteString(L"//");
					break;
				default:;
				}

				if (node->attributeNameOption == GuiIqNameOption::Specified)
				{
					writer.WriteChar(L'@');
					writer.WriteString(node->attributeName.value);
					writer.WriteChar(L':');
				}

				if (node->typeNameOption == GuiIqNameOption::Specified)
				{
					writer.WriteString(node->typeName.value);
				}
				else
				{
					writer.WriteChar(L'*');
				}

				if (node->referenceName.value != L"")
				{
					writer.WriteChar(L'.');
					writer.WriteString(node->referenceName.value);
				}
			}

			void Visit(GuiIqCascadeQuery* node)override
			{
				node->parent->Accept(this);
				node->child->Accept(this);
			}

			void Visit(GuiIqSetQuery* node)override
			{
				writer.WriteChar(L'(');
				node->first->Accept(this);
				switch (node->op)
				{
				case GuiIqBinaryOperator::ExclusiveOr:
					writer.WriteString(L" ^ ");
					break;
				case GuiIqBinaryOperator::Intersect:
					writer.WriteString(L" * ");
					break;
				case GuiIqBinaryOperator::Union:
					writer.WriteString(L" + ");
					break;
				case GuiIqBinaryOperator::Substract:
					writer.WriteString(L" - ");
					break;
				default:;
				}
				node->second->Accept(this);
				writer.WriteChar(L')');
			}
		};

		void GuiIqPrint(Ptr<GuiIqQuery> query, stream::StreamWriter& writer)
		{
			GuiIqPrintVisitor visitor(writer);
			query->Accept(&visitor);
		}
	}
}


/***********************************************************************
.\INSTANCEQUERY\GENERATED\GUIINSTANCEQUERYAST.CPP
***********************************************************************/
/***********************************************************************
This file is generated by: Vczh Parser Generator
From parser definition:Ast
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/


namespace vl::presentation::instancequery
{
/***********************************************************************
Visitor Pattern Implementation
***********************************************************************/

	void GuiIqPrimaryQuery::Accept(GuiIqQuery::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiIqCascadeQuery::Accept(GuiIqQuery::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiIqSetQuery::Accept(GuiIqQuery::IVisitor* visitor)
	{
		visitor->Visit(this);
	}
}
namespace vl::reflection::description
{
#ifndef VCZH_DEBUG_NO_REFLECTION

	IMPL_TYPE_INFO_RENAME(vl::presentation::instancequery::GuiIqQuery, presentation::instancequery::GuiIqQuery)
	IMPL_TYPE_INFO_RENAME(vl::presentation::instancequery::GuiIqQuery::IVisitor, presentation::instancequery::GuiIqQuery::IVisitor)
	IMPL_TYPE_INFO_RENAME(vl::presentation::instancequery::GuiIqNameOption, presentation::instancequery::GuiIqNameOption)
	IMPL_TYPE_INFO_RENAME(vl::presentation::instancequery::GuiIqChildOption, presentation::instancequery::GuiIqChildOption)
	IMPL_TYPE_INFO_RENAME(vl::presentation::instancequery::GuiIqPrimaryQuery, presentation::instancequery::GuiIqPrimaryQuery)
	IMPL_TYPE_INFO_RENAME(vl::presentation::instancequery::GuiIqCascadeQuery, presentation::instancequery::GuiIqCascadeQuery)
	IMPL_TYPE_INFO_RENAME(vl::presentation::instancequery::GuiIqBinaryOperator, presentation::instancequery::GuiIqBinaryOperator)
	IMPL_TYPE_INFO_RENAME(vl::presentation::instancequery::GuiIqSetQuery, presentation::instancequery::GuiIqSetQuery)

#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA

	BEGIN_CLASS_MEMBER(vl::presentation::instancequery::GuiIqQuery)
		CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)

	END_CLASS_MEMBER(vl::presentation::instancequery::GuiIqQuery)

	BEGIN_ENUM_ITEM(vl::presentation::instancequery::GuiIqNameOption)
		ENUM_ITEM_NAMESPACE(vl::presentation::instancequery::GuiIqNameOption)
		ENUM_NAMESPACE_ITEM(Specified)
		ENUM_NAMESPACE_ITEM(Any)
	END_ENUM_ITEM(vl::presentation::instancequery::GuiIqNameOption)

	BEGIN_ENUM_ITEM(vl::presentation::instancequery::GuiIqChildOption)
		ENUM_ITEM_NAMESPACE(vl::presentation::instancequery::GuiIqChildOption)
		ENUM_NAMESPACE_ITEM(Direct)
		ENUM_NAMESPACE_ITEM(Indirect)
	END_ENUM_ITEM(vl::presentation::instancequery::GuiIqChildOption)

	BEGIN_CLASS_MEMBER(vl::presentation::instancequery::GuiIqPrimaryQuery)
		CLASS_MEMBER_BASE(vl::presentation::instancequery::GuiIqQuery)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::instancequery::GuiIqPrimaryQuery>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(childOption)
		CLASS_MEMBER_FIELD(attributeNameOption)
		CLASS_MEMBER_FIELD(attributeName)
		CLASS_MEMBER_FIELD(typeNameOption)
		CLASS_MEMBER_FIELD(typeName)
		CLASS_MEMBER_FIELD(referenceName)
	END_CLASS_MEMBER(vl::presentation::instancequery::GuiIqPrimaryQuery)

	BEGIN_CLASS_MEMBER(vl::presentation::instancequery::GuiIqCascadeQuery)
		CLASS_MEMBER_BASE(vl::presentation::instancequery::GuiIqQuery)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::instancequery::GuiIqCascadeQuery>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(parent)
		CLASS_MEMBER_FIELD(child)
	END_CLASS_MEMBER(vl::presentation::instancequery::GuiIqCascadeQuery)

	BEGIN_ENUM_ITEM(vl::presentation::instancequery::GuiIqBinaryOperator)
		ENUM_ITEM_NAMESPACE(vl::presentation::instancequery::GuiIqBinaryOperator)
		ENUM_NAMESPACE_ITEM(ExclusiveOr)
		ENUM_NAMESPACE_ITEM(Intersect)
		ENUM_NAMESPACE_ITEM(Union)
		ENUM_NAMESPACE_ITEM(Substract)
	END_ENUM_ITEM(vl::presentation::instancequery::GuiIqBinaryOperator)

	BEGIN_CLASS_MEMBER(vl::presentation::instancequery::GuiIqSetQuery)
		CLASS_MEMBER_BASE(vl::presentation::instancequery::GuiIqQuery)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::instancequery::GuiIqSetQuery>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(first)
		CLASS_MEMBER_FIELD(second)
		CLASS_MEMBER_FIELD(op)
	END_CLASS_MEMBER(vl::presentation::instancequery::GuiIqSetQuery)

	BEGIN_INTERFACE_MEMBER(vl::presentation::instancequery::GuiIqQuery::IVisitor)
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::instancequery::GuiIqQuery::IVisitor::*)(vl::presentation::instancequery::GuiIqPrimaryQuery* node))
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::instancequery::GuiIqQuery::IVisitor::*)(vl::presentation::instancequery::GuiIqCascadeQuery* node))
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::instancequery::GuiIqQuery::IVisitor::*)(vl::presentation::instancequery::GuiIqSetQuery* node))
	END_INTERFACE_MEMBER(vl::presentation::instancequery::GuiIqQuery)

#endif

#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
	class GuiInstanceQueryAstTypeLoader : public vl::Object, public ITypeLoader
	{
	public:
		void Load(ITypeManager* manager)
		{
			ADD_TYPE_INFO(vl::presentation::instancequery::GuiIqQuery)
			ADD_TYPE_INFO(vl::presentation::instancequery::GuiIqQuery::IVisitor)
			ADD_TYPE_INFO(vl::presentation::instancequery::GuiIqNameOption)
			ADD_TYPE_INFO(vl::presentation::instancequery::GuiIqChildOption)
			ADD_TYPE_INFO(vl::presentation::instancequery::GuiIqPrimaryQuery)
			ADD_TYPE_INFO(vl::presentation::instancequery::GuiIqCascadeQuery)
			ADD_TYPE_INFO(vl::presentation::instancequery::GuiIqBinaryOperator)
			ADD_TYPE_INFO(vl::presentation::instancequery::GuiIqSetQuery)
		}

		void Unload(ITypeManager* manager)
		{
		}
	};
#endif
#endif

	bool GuiInstanceQueryAstLoadTypes()
	{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
		if (auto manager = GetGlobalTypeManager())
		{
			auto loader = Ptr(new GuiInstanceQueryAstTypeLoader);
			return manager->AddTypeLoader(loader);
		}
#endif
		return false;
	}
}


/***********************************************************************
.\INSTANCEQUERY\GENERATED\GUIINSTANCEQUERYPARSER.CPP
***********************************************************************/
/***********************************************************************
This file is generated by: Vczh Parser Generator
From parser definition:GuiInstanceQuery
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/


namespace vl::presentation::instancequery
{
	void GuiInstanceQueryParserData(vl::stream::IStream& outputStream)
	{
		static const vl::vint dataLength = 2815; // 27722 bytes before compressing
		static const vl::vint dataBlock = 256;
		static const vl::vint dataRemain = 255;
		static const vl::vint dataSolidRows = 10;
		static const vl::vint dataRows = 11;
		static const char* compressed[] = {
			"\x4A\x6C\x00\x00\xF7\x0A\x00\x00\x0D\x00\x01\x82\x80\x07\x03\x82\x81\x82\x06\x89\x82\x88\x0A\x87\x06\x84\x0C\x0A\x9D\x0A\x86\x1A\x87\x16\x84\x77\x02\x09\xBF\x7B\x8C\x8B\x8E\x84\x00\x1D\x9D\x9F\x81\x9C\x8B\x90\x93\x7F\x1F\x9F\x81\x0A\x8B\x91\x85\x96\x83\x27\xA8\x8A\x91\x96\x94\x91\x9B\x90\x37\xA2\xB3\x87\x99\x9D\x93\x9C\x9B\x3F\xB8\x81\xBA\x9A\x8C\x9F\xA0\x9F\x45\xC0\x89\xA2\xAB\xA4\xA0\x98\xA3\x4D\xC8\x8F\xAA\xA3\xAC\xA5\xAA\xA7\x03\xB4\x87\xBE\x8B\xAA\x99\xA8\xAE\x09\x99\xAE\x9D\xAD\x98\xB3\xAA\xA9\x59\xD0\xA7\xA6\xB9\xB4\xA9\xB6\xAB\x6F\xD8\x82\x9A\xAF\xAE\xAF\xB4\xBB\x71\xE8\x82\x83\x0C\x94\xB2\xBF\xBA\x65\xF8\xB3\xAA\xB3\x84\x01\xBE\xC0\x7F\xF7\x81\xCB\xC9\xC1\xBC\xB7\xC1\x6E\x90\xF0\xB2\xC2\xB9\x81\x03\xC3\x8A\x8D\xD4\xDA\xB1\x84\xB9\xCC\xC4\xA0\x9F\xE2\xCE\xC2\xC5\xCC\xC3\xCD\x8F\xA6\xD1\xCA\xD3\xC9\x82\x02\xCC\xA4\x8C\xE1\xD1\xDA\xCC\xD5\xCA\x90\xA7\xB6\xDC\xD8\xDB\xD4\xDD\xD6\xDF\xB7\x9E\xC3\x88\x86\x87\x94\xDB\xD9\xA8\xA5\xC0\xFB\xD2\xE3\x84\xD9\xE4\xB2\xA3\xD0\xF5\xDB\xE1\xD5\xEA\xE5\xCD\xBA\xD6\xF9",
			"\xE0\x01\x07\xE6\xED\xD8\xB9\xD7\xF1\xE7\xE2\xE8\xF0\xF2\xD3\xC8\xE7\xF4\xEC\xED\xF6\xF0\xF7\xBD\xDC\xCA\x1F\xE0\x03\x04\xFA\xF8\xBF\xF8\xC1\xE2\xFC\x07\xFB\xF7\xFF\xF1\x40\x89\x7E\x80\xFB\x41\x86\x83\x80\x07\x85\x88\x83\x82\x0A\x8D\x8C\x72\x78\x00\x63\x5A\x7B\x78\xEC\x44\x8F\x81\x82\x17\x8C\x89\x86\x83\xDB\x56\x8D\x84\x86\x1F\x9A\x81\x8B\x6D\x0E\x3E\x70\x89\x78\x27\xA8\x7B\x7B\x84\x0E\x52\x86\x78\x85\x13\xBA\x7B\x87\x8C\x23\xB4\x88\x8A\x88\x37\x9C\x89\x8F\x6E\x10\x26\x88\x8F\x47\x11\x3E\x8A\x8E\x8A\x30\xAF\x82\x8D\x8D\x48\xBB\x89\x90\x91\x47\x8A\x9E\x90\x93\xE2\x52\x04\x7F\x04\x42\xB6\x80\x95\x8A\x15\x98\x91\x8E\x87\xCA\x54\x04\x7D\x05\x55\x8B\x9A\x42\x05\x61\x8F\x99\x97\x8F\x67\x83\x99\x9A\x95\x6B\xA2\x9B\x96\x96\x46\x9C\x97\x94\x9A\x09\x57\x05\x9B\x9C\x6A\xAF\x94\x9D\x9C\x70\xA5\x7E\x9D\x7A\x7C\xBB\x9F\x9F\x8A\x81\xB9\x96\x40\x44\x2E\x83\xA5\x92\xA2\x4D\xB8\x9C\x9B\x84\x19\x34\x7A\x07\x9D\xD4\x5B\x04\xA6\x9E\x86\x8C\xA2\x9C\x75\x1C\x17\xA5\xA3\xA3\x9F\xAE\x91\xAA\x99\x98\xA0\xAA\xA5\x9F\x80\x8A\xA2\x45\xA2",
			"\x02\x5E\x0E\xA7\xA9\x82\xA9\xA2\x43\x07\xAF\xB2\xA4\xA3\x40\x20\x35\xA7\xAE\xAD\x8B\xBC\xAD\xA1\x9B\xA4\xA3\xAE\xA2\xA8\xB0\x99\xA2\x41\x08\xF4\x62\x0A\xAD\xAF\xBB\x8D\xBC\xB0\x00\x23\x0B\xBF\xAD\xA9\xD6\x64\x04\x7D\x09\xD2\xA2\x74\x44\xAB\xCE\x93\xB2\xB0\xB0\xC3\x81\xB5\xB2\xA9\xBE\x9B\xA4\xB6\xB8\xE5\xA8\xAD\xB6\xB9\x06\x67\x04\x7C\x0A\xD9\xBD\x69\x09\xBC\xB1\xAB\xBA\xBB\xB3\xDC\x6A\x04\x7F\x0A\xF4\x86\xB6\xBD\xBD\xF8\xAC\xB3\xB8\xB1\xBC\xAC\x04\x7D\x0B\xFD\xA4\xBF\xBE\xBF\x01\xF7\xBE\xB7\xC0\xE8\x8E\xBE\x08\x7D\x16\x5C\xBD\xC3\x6F\x30\x09\xC4\xC3\xC2\x0A\xD7\xCC\xC3\xC3\xE9\x80\xC0\xC8\xC7\x1B\xDE\xCD\xC7\xC8\xCF\xB1\x04\x7E\x0C\x1A\xCA\x73\x0D\xCB\xE1\xB1\xC0\xBA\x42\x34\x34\x75\x0E\x42\x62\x5F\xB7\xBA\xCC\x3B\xF3\xCD\xCF\xCF\x2F\xB7\x04\x7C\x0E\x30\xCA\x49\x0D\xD1\x40\xD0\xCC\xCE\x41\x3A\x34\x7B\x0C\xCE\x3E\xFA\xC2\xD6\xD2\x51\xD4\xD9\xD1\xC8\x1F\xE2\x7D\x0C\xD2\x53\xD8\xD7\xCA\xC0\x5E\xE5\xC8\xCB\xD8\xE2\x7E\x0C\xD6\xD5\x5D\xC1\x4F\x0C\x7D\x40\x10\xD7\xD4\xC9\x11\xE6\xC2\xD8\xD8\x70\xCB\xDA\xA2\x10\xF4",
			"\x43\x17\xDA\x40\x44\x3B\xD5\xDD\xD5\x61\xF1\xD4\xDA\xC3\x74\xF2\xD2\xE1\xE1\x83\xE2\xC2\x79\x11\xF4\x46\x1E\xDC\x00\x47\x0F\xE9\xE1\xD6\xF7\x88\x14\x7D\x12\x6E\xE9\xD6\xE2\xDD\x81\xDC\xEF\xDF\xDB\xCF\x8B\x14\x7C\x13\x8F\xCD\x12\xE4\xE2\xA8\xF7\xBE\x10\x7D\x4F\x19\xE8\xDB\xEB\x9D\xC0\xEF\xE6\xE6\x93\xDF\xD4\xE3\xED\x00\xD1\x17\xE8\xEE\x94\xCA\xEC\xEE\xED\xBE\xFF\x62\x17\xEE\x00\xD3\x14\x7C\x15\xAE\xF1\xE0\xE9\xED\x73\xFF\xED\xF1\xF0\xB7\x56\x14\x7F\x15\x8F\xD8\x14\xF1\xEF\xD8\xC0\xF9\xF7\xF3\xDB\xC7\xEE\xF2\xF7\xD0\xFB\x69\x17\xF5\xDA\xE5\xFC\xF6\xF9\xE0\xCC\xCB\x02\x71\x01\x79\xC4\x68\xCA\xEE\xC9\x78\xC8\xFB\x01\x74\xF0\x00\x5F\x09\x46\x66\xC5\x4C\x97\x49\x4D\xFE\x41\xF1\x76\x32\x42\x44\x33\x20\xFC\x46\x24\x80\xF2\x7C\x4A\xFD\x01\x31\x80\x00\x36\x7E\x7E\x06\x85\x31\x99\x7F\x73\x20\x0A\x82\x25\x81\x16\x81\x20\x02\x81\x21\x83\x83\x1D\x29\x26\x0B\x8A\x21\x07\x81\x2A\x7F\xE2\x1D\x29\x83\x00\x0F\x35\x4A\x06\x28\x84\x14\x98\x83\x80\x22\x90\x85\x5D\x4D\x41\x85\xBA\x0D\x85\x86\x06\x23\x84\x00\x25\x83\x20\xFB\x7C\x7A",
			"\x21\x2A\x8B\x86\x40\x2D\x89\x78\x01\x89\x23\x83\xF7\x72\x87\x5D\x31\x2D\x81\x98\x30\x7F\x83\x85\x6D\x8A\x13\xF7\x5F\x80\xFA\x28\x82\x87\xF6\x68\x8B\x14\xA7\x48\x86\xD2\x0D\x84\x81\xF4\x3F\x20\x0F\xC3\x85\x88\x07\x8A\x27\x8A\x0A\x23\x8E\x06\xD0\x84\x24\x29\x9B\x8D\x63\x6E\x8F\x8D\xDC\x71\x8F\x8C\x22\x74\x8B\x8B\x76\x8C\x8C\xC0\x5A\x82\x8F\x24\x4D\x87\x8E\x53\x99\x8F\x0C\xD1\x8A\x8E\x86\x5D\x8F\x82\x67\x89\x8D\x19\xFC\x8D\x8E\x40\x8E\x8A\x90\x4B\x84\x93\x20\xD4\x84\x3F\x17\xB9\x7B\x91\x85\x9C\x22\x23\xCF\x83\x92\x80\x5B\x92\x92\x91\x97\x5F\x27\xA2\x99\x93\x92\x63\x96\x93\xA5\x93\x8D\x2A\xC4\x4A\x8D\x94\x3F\x86\x62\x1F\x28\x86\x4A\x4A\x8F\x7D\x93\x2D\x91\x30\x28\x87\x92\x11\xC2\x85\x7E\x5A\x89\x85\x8D\xA9\x9A\x84\x77\x0C\x92\x8E\x62\xAF\x8F\x94\x1D\x22\x9A\x78\x48\x90\x8F\x55\x94\x3C\x99\xA6\x8E\x9B\x84\x50\x9A\x95\x4E\x86\x94\x3E\x3A\x8D\x96\x32\xA4\x28\x84\x86\x3C\x93\x97\x03\x33\x3D\x58\x09\x99\x20\xEF\x09\x22\x87\xC6\x9B\x89\x15\xE7\x9A\x90\x76\xB5\x2D\x9B\xDF\x80\x9E\x40\x62\x90\x80\x72\x86\x26\x9C\x39\x9E",
			"\x94\x78\x4C\x81\x98\xEA\x2B\x99\x9F\x97\x8E\x9F\x5D\x70\x91\x9E\x14\xB4\x9B\x20\x96\x97\x9D\x0C\xC7\x89\x94\x6A\x9B\x9F\x37\xD4\x90\x91\x2D\xA4\x96\x9B\x8E\x7A\x91\x89\x01\xA0\xA3\x40\x8A\x2E\x9B\x6F\x86\xA5\x8C\x28\x98\x9D\x01\xFA\x97\x3A\x10\xB1\x98\xA3\x06\x3A\x9B\x09\x9C\xA7\xA5\x8F\xA3\x9E\x7F\x0A\x22\xA7\x5E\x24\xAD\x8F\x8D\x0E\xA6\x9F\x27\xB9\x9B\x42\x9B\xA9\x21\x8E\xBC\x96\xA5\xF5\x90\xA5\x39\xBB\xA3\x39\x86\xBD\x9B\x42\x81\x37\xA2\x49\x8C\xA5\xA3\x8D\x29\x9B\x8A\x37\xB3\x43\x53\xCE\x81\xAB\x17\x51\xA7\x99\xD2\x96\xA9\x56\x8A\x57\xAB\x69\x9B\xAC\x57\x5D\xAF\x46\xFD\x0D\x8A\xA6\x81\xA4\x34\xA0\x1E\xAA\x23\x41\x88\x92\xA8\x85\xA6\xAE\x83\x4D\xBF\x1F\x58\xC4\xA2\x20\x95\xAF\x9C\xA5\x05\xAA\xAC\x48\xB1\xA4\xAF\x35\xB1\xAD\xAA\x8A\x53\xAF\x5B\xA4\x8D\xAF\xEB\x28\xAF\xA7\x7A\xAF\xA4\x0B\xFC\xA3\xB0\x82\x06\xA9\xAE\x0F\xB7\x35\x58\xDC\xAF\xAA\x67\x53\xB4\x57\x10\x85\xB2\x5D\xBC\xA6\x20\x9F\x82\x88\xA8\x08\xB6\x9F\x40\x32\xAC\x82\x9A\xB5\xA1\xB3\x8D\xBB\xB3\x59\xF8\xA9\xAD\x84\x2B\xAD\x7D\xA2\xA2\x20\x69\xA8",
			"\xA5\xA9\xBF\x87\xAA\xAC\x85\xA5\xAE\x46\xAB\xBD\xA7\x96\x89\xB1\xA8\x8B\xA3\xA9\x63\xD3\xAC\x9E\xC8\x94\x39\xA9\x27\xAB\xAB\x01\xA9\x94\xB9\x93\x00\xB4\x57\xCD\xA0\x9A\x71\xDE\xA1\xAE\x89\xBF\x90\x95\xD5\xB4\x39\x74\xA1\x24\x9B\xEE\x8F\xB1\x94\xDC\xB7\xB4\x69\x28\xB7\x2E\xB2\x9D\x2E\xBC\x36\x85\xB1\x71\x86\x2C\x0B\x93\xB3\x96\x62\xE8\xA9\xA5\x6C\xAE\x35\x8C\xDD\x95\x80\x88\xF5\xAD\x9D\x70\x86\x21\x89\xDA\x9F\x98\x89\x1F\x28\x8A\x67\xAB\x83\xC1\x94\x05\xC5\xBF\x02\x28\xC0\x7D\xC2\xBE\xAD\x06\xF7\xB9\x21\x0A\xC0\x00\x0A\x91\xC3\xC3\xDF\x83\x21\xC2\xAF\xA9\x86\x85\x89\xCA\x20\xFB\x10\xC5\xC3\xF8\xA9\x22\x87\xFC\xBA\xBF\x07\xE4\xC1\xA3\x26\xD7\xC1\x89\xE4\x8F\xC3\x84\x3D\x3D\xAD\x2A\xCE\xC7\x7C\x9A\xC2\xC6\x18\xDC\xC1\x21\x11\x5B\xBD\x8C\x86\x29\xC7\x14\xF7\xC4\xC7\x33\xD1\xC2\x7D\xAC\xC7\xC5\xDD\xB5\xA9\xC8\x9A\xA8\xC9\x3C\xA5\x41\x9F\x0C\xDC\x38\x8B\xF4\x77\xA1\x8F\xBC\x51\xB3\xDD\x11\xC2\x4A\x13\x55\xCA\x75\x28\x8A\x65\x2C\xF8\x61\xCA\x2B\xC1\x23\xC4\x5E\xC7\x9C\x30\xCD\xB0\x5B\x64\xC9\xA6\x99\xC0\xB3\x21\x4E",
			"\x69\xCD\x82\x6B\xDD\x86\x42\x5E\x4F\xCC\xCC\xA3\x4C\x3A\x5A\xCA\x39\x03\x96\x58\xA8\x20\xB1\xCB\xA6\x09\x39\x55\x9F\xC7\x8F\xCF\xD2\x89\x22\x59\x83\xDD\xB1\xA1\xBB\x8A\x21\x79\x49\xD3\xB4\x8B\xCD\x94\xBF\x0F\xD3\x9F\x45\xDA\x0E\xB7\xA0\x7F\x22\x23\xEE\xBB\xD2\xAC\x8A\xB4\xB2\xFB\x65\x71\x2B\xA8\x8C\x3B\xF8\xB0\x71\x20\xB3\xBE\x86\x78\x43\xC3\x77\x70\x8B\x5D\x95\xAA\xD7\x5F\x88\xBE\xCE\x59\x5C\xB2\x70\x00\x3D\x4D\xC7\x8B\x15\xC0\x74\x32\x61\xD5\x37\x11\xD3\xA8\x91\x76\x4F\xD7\xDF\x08\x89\xD6\x00\x68\x51\x91\x8A\x55\xC0\x52\xC5\x76\x55\x9F\xC2\x8A\xFD\x05\xCD\xD3\x09\x42\xD4\xCD\x02\x3F\x9F\x40\x05\xC3\xD6\xE5\x46\x20\xD1\xD8\xCE\x59\x86\xB3\xB8\x64\x6B\x4D\xB4\x3B\xDD\xC1\x23\x8B\x9A\x7E\x5D\x62\xF7\x31\xDD\x00\x0C\xCA\xE6\x70\x5E\xDD\xDD\x2B\xDB\x20\xF2\xC7\xD4\x00\x0E\xD6\x85\x09\x53\xC8\xD5\xB7\xDA\x5C\x8A\xBC\x59\xDE\x22\xFA\xDB\xCC\xE1\xC0\x03\x0D\x8A\x25\xE0\xD8\xA0\x71\x63\xD1\xC6\xD1\xBF\x86\x2D\x44\x83\x04\xDA\x73\x2C\x71\xE3\xB3\x15\xE3\x20\x30\x60\x75\x66\x1A\xFC\x38\xC7\x82\x24\x4A\xD0\x76\x05\x8C",
			"\xDC\x21\x49\x42\x39\xDA\x72\xA2\x75\xDE\x3A\x58\xC6\x22\xCA\x9A\x77\x69\x97\xCA\x3D\xE4\x16\xF7\xD5\xD3\x1A\xE3\xD4\x85\x38\xE5\xE3\xB7\xDC\x05\x19\xB3\xB8\x85\x9F\xE4\xE7\xD6\x66\x7A\xE1\xC3\x92\xC3\xCE\x85\x2C\xE2\xDF\x6D\x67\xDE\x78\x1E\xEA\xC6\x6F\xC3\x22\x6F\x1A\xE6\xEA\xC3\x86\x24\xEB\xD0\xA0\x74\x71\x1A\xFD\xE8\x5B\xDC\xE0\xC4\xD0\x51\x72\xE3\x17\xF2\xCD\x42\x3E\xD6\x21\xA7\xD6\xEA\x20\x98\x72\xE9\x6F\x69\xE6\xE1\xB7\xC1\x24\x74\x1A\xEA\xDA\xD7\xB9\xE1\xE5\xC2\x6B\x72\xE3\x93\x48\xED\xD9\x9A\x70\x0B\x32\xAE\xCB\xE2\x03\x3A\xEE\x40\x74\xED\xD4\x81\x03\x7A\xE3\xAB\x48\xF2\x40\x0A\xF1\x20\xB1\xCD\xF1\x20\xC8\x7A\xE0\xB4\x92\xF1\x20\xCA\xC0\x02\xEB\x9B\x6A\x22\xF4\x1A\xE4\x56\x8B\x41\xF4\xEF\x9A\x76\x7A\xC6\xD7\xDA\xEC\x83\x27\xF0\xE8\xA0\x77\xD2\xC6\xC8\x56\xF4\x9F\xF7\xD5\xBD\x1A\xE0\xDD\xEB\x83\x2C\xCE\x83\x11\x50\x74\x5E\x01\xCF\xB3\x3D\xF3\x21\xD7\xF6\xE8\x00\x62\x01\xC7\x8B\x07\xF3\x21\xDF\xDA\x70\x0D\xCB\x4C\xFA\x40\x46\xF7\xF2\x00\x29\x0A\xBD\xE2\x31\xF3\x40\x0C\xF1\xF5\x84\x2C\x0D\x8C\xD1\x50\xF2",
			"\x42\x16\xFD\xFA\x83\x2E\x0D\x8C\x68\xC9\xE2\xF6\xC7\xE0\x74\x38\x25\x8D\xDD\x09\xE5\xF4\xEA\xFA\xD2\x0F\x32\xBC\xDB\xEF\x03\x32\xFC\xEC\x9A\x74\x0F\x32\x93\xD1\xFE\xB6\x70\x3A\x76\x05\x46\x08\x3B\x7A\x0A\x1B\x79\xFA\x68\x07\xCA\x7A\x28\xAC\x72\x10\xE1\x7A\x39\x7E\x0C\x5A\x0C\x8A\x10\xE6\x6A\x39\x86\x02\x81\xBC\x24\x7B\xF3\x77\x7C\x8E\x05\x46\x15\x39\x70\x1A\x8B\x7F\xFA\x60\x09\x65\x4D\x65\x20\x81\x80\x9A\x32\x09\x65\x4F\x32\xB9\x77\x80\xB7\x64\x09\x0B\x8C\x2B\xBA\x7E\x80\xB7\x6A\x09\x18\x8E\x2C\x33\x81\x10\x15\x8A\x6F\xA2\x07\x83\xCF\x2F\x80\xF9\x77\x6B\xAA\x0B\x2C\x3B\x87\x2C\xB7\x6B\x0A\xCB\x29\x7E\x03\x18\x80\xC7\x7C\x0A\x49\x8A\x10\x40\x87\x7C\xAD\x08\x7D\xBD\x1A\x84\x02\x15\x84\xD5\x70\x0B\x54\x8F\x1B\xDB\x2B\x81\xD5\x73\x0B\x65\x47\x33\x8D\x5D\x85\x22\x87\x7C\xB5\x05\x46\x2E\x76\x64\x01\x14\x86\xEC\x7A\x39\xB7\x05\x46\x4F\x3D\x58\xF4\x6E\x85\xE5\x73\x10\xB9\x05\x46\x49\x7A\x86\x00\x03\x87\x65\x85\x7D\xBB\x05\x46\x41\x05\x58\x7C\x8D\x86\xFA\x6D\x0B\x65\x4D\x37\x8D\x57\x7F\x02\x10\x7F\xFA\x6F\x0B\x31\x8E",
			"\x2C\x8A\x81\x10\x06\x30\x3A\xC5\x0E\x83\xDC\x11\x89\x00\x05\x80\x9A\x3D\x0C\x96\x82\x1E\x02\x74\x87\x28\x35\x0D\x65\x47\x76\x7A\x8F\x89\x7D\x85\x87\x02\x17\x0D\x65\x4A\x04\x85\x56\x8A\x84\x87\x7C\xD9\x05\x46\xA6\x3D\x58\xFF\x73\x10\x8C\x87\x7C\xDB\x0F\x88\xCF\x25\x8B\x02\x13\x89\x9A\x31\x0E\x9D\x8D\x1B\xBC\x81\x10\x9A\x8A\x6F\xE9\x01\x8C\xBF\x1E\x8B\x03\x13\x88\xD5\x71\x0F\xCB\x25\x8C\x02\x1E\x8A\xD5\x72\x0F\xCB\x28\x70\xB6\x87\x6B\xF3\x05\x8D\x0A\x1A\x8C\xC7\x74\x0F\x5B\x87\x1B\xD6\x82\x10\xD0\x85\x7D\xF7\x0F\x8D\xBB\x1F\x81\xDB\x77\x6B\xFA\x05\x46\x85\x73\x70\x01\x18\x8E\x02\x14\x7E\x28\x3C\x0F\x65\x49\x79\xF2\x59\x10\xF0\x81\x10\xA0\x78\x32\xFE\x05\x46\xAA\x77\x8F\x06\x16\x82\x03\x10\x71\x9A\x36\x46\x9C\x7F\x2C\x19\x7E\x5E\x1A\x1A\x90\x0C\x9D\x90\x0B\x4E\x43\x0F\x9F\x5E\xB0\x4B\x40\x5F\x4D\x44\x15\x9A\x69\x18\x95\x46\x0A\x79\x91\x8D\x54\x5B\x73\x1A\x43\x1E\x90\x68\xEE\x84\x58\x1A\x17\x4B\x26\x92\x46\x28\x92\x7C\x8C\x63\x63\x4C\x7A\x11\xB2\x4F\x92\xB1\x41\x93\x2C\x92\x4B\x11\x64\x63\x30\x15\x93\x1F\x10",
		};
		vl::glr::DecompressSerializedData(compressed, true, dataSolidRows, dataRows, dataBlock, dataRemain, outputStream);
	}

	const wchar_t* ParserRuleName(vl::vint index)
	{
		static const wchar_t* results[] = {
			L"QPrimaryFragment",
			L"QPrimaryAttributed",
			L"QPrimary",
			L"Query0",
			L"Query1",
			L"Query2",
			L"QueryRoot",
		};
		return results[index];
	}

	const wchar_t* ParserStateLabel(vl::vint index)
	{
		static const wchar_t* results[] = {
			L"[0][QPrimaryFragment] BEGIN ",
			L"[1][QPrimaryFragment] END [ENDING]",
			L"[2][QPrimaryFragment]< \"*\" @ [ \".\" NAME ] >",
			L"[3][QPrimaryFragment]< \"*\" [ \".\" @ NAME ] >",
			L"[4][QPrimaryFragment]< \"*\" [ \".\" NAME @ ] >",
			L"[5][QPrimaryFragment]< NAME @ [ \".\" NAME ] >",
			L"[6][QPrimaryFragment]< NAME [ \".\" @ NAME ] >",
			L"[7][QPrimaryFragment]< NAME [ \".\" NAME @ ] >",
			L"[8][QPrimaryAttributed] BEGIN ",
			L"[9][QPrimaryAttributed] END [ENDING]",
			L"[10][QPrimaryAttributed]<! !QPrimaryFragment @ !>",
			L"[11][QPrimaryAttributed]<! \"@\" @ [ NAME ] \":\" !QPrimaryFragment !>",
			L"[12][QPrimaryAttributed]<! \"@\" [ NAME @ ] \":\" !QPrimaryFragment !>",
			L"[13][QPrimaryAttributed]<! \"@\" [ NAME ] \":\" !QPrimaryFragment @ !>",
			L"[14][QPrimaryAttributed]<! \"@\" [ NAME ] \":\" @ !QPrimaryFragment !>",
			L"[15][QPrimary] BEGIN ",
			L"[16][QPrimary] END [ENDING]",
			L"[17][QPrimary]<! \"(\" !QueryRoot \")\" @ !>",
			L"[18][QPrimary]<! \"(\" !QueryRoot @ \")\" !>",
			L"[19][QPrimary]<! \"(\" @ !QueryRoot \")\" !>",
			L"[20][QPrimary]<! \"/\" !QPrimaryAttributed @ !>",
			L"[21][QPrimary]<! \"/\" @ !QPrimaryAttributed !>",
			L"[22][QPrimary]<! \"//\" !QPrimaryAttributed @ !>",
			L"[23][QPrimary]<! \"//\" @ !QPrimaryAttributed !>",
			L"[24][Query0] BEGIN ",
			L"[25][Query0] END [ENDING]",
			L"[26][Query0]< Query0 @ QPrimary >",
			L"[27][Query0]< Query0 QPrimary @ >",
			L"[28][Query0]<! !QPrimary @ !>",
			L"[29][Query1] BEGIN ",
			L"[30][Query1] END [ENDING]",
			L"[31][Query1]< Query1 \"*\" @ Query0 >",
			L"[32][Query1]< Query1 \"*\" Query0 @ >",
			L"[33][Query1]< Query1 \"^\" @ Query0 >",
			L"[34][Query1]< Query1 \"^\" Query0 @ >",
			L"[35][Query1]< Query1 @ \"*\" Query0 >",
			L"[36][Query1]< Query1 @ \"^\" Query0 >",
			L"[37][Query1]<! !Query0 @ !>",
			L"[38][Query2] BEGIN ",
			L"[39][Query2] END [ENDING]",
			L"[40][Query2]< Query2 \"+\" @ Query1 >",
			L"[41][Query2]< Query2 \"+\" Query1 @ >",
			L"[42][Query2]< Query2 \"-\" @ Query1 >",
			L"[43][Query2]< Query2 \"-\" Query1 @ >",
			L"[44][Query2]< Query2 @ \"+\" Query1 >",
			L"[45][Query2]< Query2 @ \"-\" Query1 >",
			L"[46][Query2]<! !Query1 @ !>",
			L"[47][QueryRoot] BEGIN ",
			L"[48][QueryRoot] END [ENDING]",
			L"[49][QueryRoot]<! !Query2 @ !>",
		};
		return results[index];
	}

	Parser::Parser()
		: vl::glr::ParserBase<GuiInstanceQueryTokens, ParserStates, GuiInstanceQueryAstInsReceiver>(&GuiInstanceQueryTokenDeleter, &GuiInstanceQueryLexerData, &GuiInstanceQueryParserData)
	{
	}

	vl::WString Parser::GetClassName(vl::vint32_t classIndex) const
	{
		return vl::WString::Unmanaged(GuiInstanceQueryTypeName((GuiInstanceQueryClasses)classIndex));
	}

	vl::vint32_t Parser::FindCommonBaseClass(vl::vint32_t class1, vl::vint32_t class2) const
	{
		return -1;
	}

	vl::Ptr<vl::presentation::instancequery::GuiIqQuery> Parser::ParseQueryRoot(const vl::WString& input, vl::vint codeIndex) const
	{
		 return ParseWithString<vl::presentation::instancequery::GuiIqQuery, ParserStates::QueryRoot>(input, this, codeIndex);
	}

	vl::Ptr<vl::presentation::instancequery::GuiIqQuery> Parser::ParseQueryRoot(vl::collections::List<vl::regex::RegexToken>& tokens, vl::vint codeIndex) const
	{
		 return ParseWithTokens<vl::presentation::instancequery::GuiIqQuery, ParserStates::QueryRoot>(tokens, this, codeIndex);
	}
}


/***********************************************************************
.\INSTANCEQUERY\GENERATED\GUIINSTANCEQUERY_ASSEMBLER.CPP
***********************************************************************/
/***********************************************************************
This file is generated by: Vczh Parser Generator
From parser definition:GuiInstanceQuery
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/


namespace vl::presentation::instancequery
{

/***********************************************************************
GuiInstanceQueryAstInsReceiver : public vl::glr::AstInsReceiverBase
***********************************************************************/

	vl::Ptr<vl::glr::ParsingAstBase> GuiInstanceQueryAstInsReceiver::CreateAstNode(vl::vint32_t type)
	{
		auto cppTypeName = GuiInstanceQueryCppTypeName((GuiInstanceQueryClasses)type);
		switch((GuiInstanceQueryClasses)type)
		{
		case GuiInstanceQueryClasses::CascadeQuery:
			return vl::Ptr(new vl::presentation::instancequery::GuiIqCascadeQuery);
		case GuiInstanceQueryClasses::PrimaryQuery:
			return vl::Ptr(new vl::presentation::instancequery::GuiIqPrimaryQuery);
		case GuiInstanceQueryClasses::SetQuery:
			return vl::Ptr(new vl::presentation::instancequery::GuiIqSetQuery);
		default:
			return vl::glr::AssemblyThrowCannotCreateAbstractType(type, cppTypeName);
		}
	}

	void GuiInstanceQueryAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::Ptr<vl::glr::ParsingAstBase> value)
	{
		auto cppFieldName = GuiInstanceQueryCppFieldName((GuiInstanceQueryFields)field);
		switch((GuiInstanceQueryFields)field)
		{
		case GuiInstanceQueryFields::CascadeQuery_child:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::instancequery::GuiIqCascadeQuery::child, object, field, value, cppFieldName);
		case GuiInstanceQueryFields::CascadeQuery_parent:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::instancequery::GuiIqCascadeQuery::parent, object, field, value, cppFieldName);
		case GuiInstanceQueryFields::SetQuery_first:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::instancequery::GuiIqSetQuery::first, object, field, value, cppFieldName);
		case GuiInstanceQueryFields::SetQuery_second:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::instancequery::GuiIqSetQuery::second, object, field, value, cppFieldName);
		default:
			return vl::glr::AssemblyThrowFieldNotObject(field, cppFieldName);
		}
	}

	void GuiInstanceQueryAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, const vl::regex::RegexToken& token, vl::vint32_t tokenIndex)
	{
		auto cppFieldName = GuiInstanceQueryCppFieldName((GuiInstanceQueryFields)field);
		switch((GuiInstanceQueryFields)field)
		{
		case GuiInstanceQueryFields::PrimaryQuery_attributeName:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::instancequery::GuiIqPrimaryQuery::attributeName, object, field, token, tokenIndex, cppFieldName);
		case GuiInstanceQueryFields::PrimaryQuery_referenceName:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::instancequery::GuiIqPrimaryQuery::referenceName, object, field, token, tokenIndex, cppFieldName);
		case GuiInstanceQueryFields::PrimaryQuery_typeName:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::instancequery::GuiIqPrimaryQuery::typeName, object, field, token, tokenIndex, cppFieldName);
		default:
			return vl::glr::AssemblyThrowFieldNotToken(field, cppFieldName);
		}
	}

	void GuiInstanceQueryAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::vint32_t enumItem, bool weakAssignment)
	{
		auto cppFieldName = GuiInstanceQueryCppFieldName((GuiInstanceQueryFields)field);
		switch((GuiInstanceQueryFields)field)
		{
		case GuiInstanceQueryFields::PrimaryQuery_attributeNameOption:
			return vl::glr::AssemblerSetEnumField(&vl::presentation::instancequery::GuiIqPrimaryQuery::attributeNameOption, object, field, enumItem, weakAssignment, cppFieldName);
		case GuiInstanceQueryFields::PrimaryQuery_childOption:
			return vl::glr::AssemblerSetEnumField(&vl::presentation::instancequery::GuiIqPrimaryQuery::childOption, object, field, enumItem, weakAssignment, cppFieldName);
		case GuiInstanceQueryFields::PrimaryQuery_typeNameOption:
			return vl::glr::AssemblerSetEnumField(&vl::presentation::instancequery::GuiIqPrimaryQuery::typeNameOption, object, field, enumItem, weakAssignment, cppFieldName);
		case GuiInstanceQueryFields::SetQuery_op:
			return vl::glr::AssemblerSetEnumField(&vl::presentation::instancequery::GuiIqSetQuery::op, object, field, enumItem, weakAssignment, cppFieldName);
		default:
			return vl::glr::AssemblyThrowFieldNotEnum(field, cppFieldName);
		}
	}

	const wchar_t* GuiInstanceQueryTypeName(GuiInstanceQueryClasses type)
	{
		const wchar_t* results[] = {
			L"CascadeQuery",
			L"PrimaryQuery",
			L"Query",
			L"SetQuery",
		};
		vl::vint index = (vl::vint)type;
		return 0 <= index && index < 4 ? results[index] : nullptr;
	}

	const wchar_t* GuiInstanceQueryCppTypeName(GuiInstanceQueryClasses type)
	{
		const wchar_t* results[] = {
			L"vl::presentation::instancequery::GuiIqCascadeQuery",
			L"vl::presentation::instancequery::GuiIqPrimaryQuery",
			L"vl::presentation::instancequery::GuiIqQuery",
			L"vl::presentation::instancequery::GuiIqSetQuery",
		};
		vl::vint index = (vl::vint)type;
		return 0 <= index && index < 4 ? results[index] : nullptr;
	}

	const wchar_t* GuiInstanceQueryFieldName(GuiInstanceQueryFields field)
	{
		const wchar_t* results[] = {
			L"CascadeQuery::child",
			L"CascadeQuery::parent",
			L"PrimaryQuery::attributeName",
			L"PrimaryQuery::attributeNameOption",
			L"PrimaryQuery::childOption",
			L"PrimaryQuery::referenceName",
			L"PrimaryQuery::typeName",
			L"PrimaryQuery::typeNameOption",
			L"SetQuery::first",
			L"SetQuery::op",
			L"SetQuery::second",
		};
		vl::vint index = (vl::vint)field;
		return 0 <= index && index < 11 ? results[index] : nullptr;
	}

	const wchar_t* GuiInstanceQueryCppFieldName(GuiInstanceQueryFields field)
	{
		const wchar_t* results[] = {
			L"vl::presentation::instancequery::GuiIqCascadeQuery::child",
			L"vl::presentation::instancequery::GuiIqCascadeQuery::parent",
			L"vl::presentation::instancequery::GuiIqPrimaryQuery::attributeName",
			L"vl::presentation::instancequery::GuiIqPrimaryQuery::attributeNameOption",
			L"vl::presentation::instancequery::GuiIqPrimaryQuery::childOption",
			L"vl::presentation::instancequery::GuiIqPrimaryQuery::referenceName",
			L"vl::presentation::instancequery::GuiIqPrimaryQuery::typeName",
			L"vl::presentation::instancequery::GuiIqPrimaryQuery::typeNameOption",
			L"vl::presentation::instancequery::GuiIqSetQuery::first",
			L"vl::presentation::instancequery::GuiIqSetQuery::op",
			L"vl::presentation::instancequery::GuiIqSetQuery::second",
		};
		vl::vint index = (vl::vint)field;
		return 0 <= index && index < 11 ? results[index] : nullptr;
	}

	vl::Ptr<vl::glr::ParsingAstBase> GuiInstanceQueryAstInsReceiver::ResolveAmbiguity(vl::vint32_t type, vl::collections::Array<vl::Ptr<vl::glr::ParsingAstBase>>& candidates)
	{
		auto cppTypeName = GuiInstanceQueryCppTypeName((GuiInstanceQueryClasses)type);
		return vl::glr::AssemblyThrowTypeNotAllowAmbiguity(type, cppTypeName);
	}
}


/***********************************************************************
.\INSTANCEQUERY\GENERATED\GUIINSTANCEQUERY_LEXER.CPP
***********************************************************************/
/***********************************************************************
This file is generated by: Vczh Parser Generator
From parser definition:GuiInstanceQuery
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/


namespace vl::presentation::instancequery
{
	bool GuiInstanceQueryTokenDeleter(vl::vint token)
	{
		switch((GuiInstanceQueryTokens)token)
		{
		case GuiInstanceQueryTokens::SPACE:
			return true;
		default:
			return false;
		}
	}

	const wchar_t* GuiInstanceQueryTokenId(GuiInstanceQueryTokens token)
	{
		static const wchar_t* results[] = {
			L"INDIRECT",
			L"DIRECT",
			L"NAME",
			L"WILDCARD_INTERSECT",
			L"OPEN",
			L"CLOSE",
			L"XOR",
			L"UNION",
			L"SUBSTRACT",
			L"ATTRIBUTE",
			L"COLON",
			L"DOT",
			L"SPACE",
		};
		vl::vint index = (vl::vint)token;
		return 0 <= index && index < GuiInstanceQueryTokenCount ? results[index] : nullptr;
	}

	const wchar_t* GuiInstanceQueryTokenDisplayText(GuiInstanceQueryTokens token)
	{
		static const wchar_t* results[] = {
			L"//",
			L"/",
			nullptr,
			L"*",
			L"(",
			L")",
			L"^",
			L"+",
			L"-",
			L"@",
			L":",
			L".",
			nullptr,
		};
		vl::vint index = (vl::vint)token;
		return 0 <= index && index < GuiInstanceQueryTokenCount ? results[index] : nullptr;
	}

	const wchar_t* GuiInstanceQueryTokenRegex(GuiInstanceQueryTokens token)
	{
		static const wchar_t* results[] = {
			L"////",
			L"//",
			L"[a-zA-Z_][a-zA-Z0-9]*",
			L"/*",
			L"/(",
			L"/)",
			L"/^",
			L"/+",
			L"-",
			L"@",
			L":",
			L".",
			L"/s+",
		};
		vl::vint index = (vl::vint)token;
		return 0 <= index && index < GuiInstanceQueryTokenCount ? results[index] : nullptr;
	}

	void GuiInstanceQueryLexerData(vl::stream::IStream& outputStream)
	{
		static const vl::vint dataLength = 232; // 1446 bytes before compressing
		static const vl::vint dataBlock = 256;
		static const vl::vint dataRemain = 232;
		static const vl::vint dataSolidRows = 0;
		static const vl::vint dataRows = 1;
		static const char* compressed[] = {
			"\xA6\x05\x00\x00\xE0\x00\x00\x00\x10\x00\x01\x93\x01\x84\x81\x82\x08\x82\x09\x08\x84\x8A\x0B\x84\x81\x06\x87\x04\xA0\x11\x84\x88\x14\x88\x83\x14\x17\x84\xAA\x1A\x84\x83\x15\x8E\x82\x2D\x20\x84\x8E\x13\x94\x83\x16\x93\x04\xB0\x04\x99\x14\x82\x1D\x96\x82\x40\x30\x84\x81\x24\x82\x2C\x82\x2F\x37\x84\x9F\x3A\x94\x81\x30\x82\x3D\x04\x8C\x01\xA3\xA1\x82\xA1\x80\x02\x04\x85\x04\x83\x04\x87\x00\x82\x04\x04\x8B\x04\x81\x04\x87\x7E\xAB\x7F\x0C\x81\x89\x81\x82\x04\x82\x02\x82\x5D\xDC\x95\xB7\xA4\xB5\xB2\xB3\xB3\x68\xE9\xBF\x6F\x81\x82\xB6\xB7\xB7\x70\xF1\xB2\xBF\x7E\x03\xB2\xB3\xBA\x6D\xE7\xB8\xA0\x03\xBD\xBE\xBF\xBF\x80\x81\xC2\xC3\xC4\xC5\xC2\xC3\xC3\x88\x89\xCA\xCB\xCC\xC5\xC6\xC7\xC7\x90\x91\xD2\xD3\xC8\xC7\x04\x82\xCB\x01\x98\xC0\x1A\xC4\xCD\xCE\xCF\xCF\x71\xFB\xA8\xA2\xDA\xBE\xBB\x7E\xCD\xA8\x97\xE6\xC0\xDF\xB6\x7F\x7E\x80\x05\x81\x94\xA2\xB1\x84\xA7\xA3\xA4\x5E\xCD\x8F\xAA\x81\x81\xAC\x00\xA9\x45\xB1\xF4\xC0\x06\xA0\x00",
		};
		vl::glr::DecompressSerializedData(compressed, true, dataSolidRows, dataRows, dataBlock, dataRemain, outputStream);
	}
}


/***********************************************************************
.\REMOTEPROTOCOL\GUIREMOTEPROTOCOLCOMPILER.CPP
***********************************************************************/

namespace vl::presentation
{
	using namespace collections;
	using namespace remoteprotocol;

/***********************************************************************
CheckRemoteProtocolSchema
***********************************************************************/

	class GuiRpCheckSchemaVisitor
		: public Object
		, public GuiRpType::IVisitor
		, public GuiRpDeclaration::IVisitor
	{
	protected:
		Ptr<GuiRpSymbols>			symbols;
		List<GuiRpError>&			errors;

	public:
		GuiRpCheckSchemaVisitor(Ptr<GuiRpSymbols> _symbols, List<GuiRpError>& _errors)
			: symbols(_symbols)
			, errors(_errors)
		{
		}

		// GuiRpType::IVisitor

		void Visit(GuiRpPrimitiveType* node) override
		{
		}

		void Visit(GuiRpReferenceType* node) override
		{
			if (symbols->enumDecls.Keys().Contains(node->name.value)) return;
			if (symbols->unionDecls.Keys().Contains(node->name.value)) return;
			if (symbols->structDecls.Keys().Contains(node->name.value)) return;
			errors.Add({ node->name.codeRange,L"Custom type \"" + node->name.value + L"\" not found." });
		}

		void Visit(GuiRpOptionalType* node) override
		{
			node->element->Accept(this);
		}

		void Visit(GuiRpArrayType* node) override
		{
			node->element->Accept(this);
		}

		void Visit(GuiRpArrayMapType* node) override
		{
			vint index = symbols->structDecls.Keys().IndexOf(node->element.value);
			if (index == -1)
			{
				errors.Add({ node->element.codeRange,L"Struct \"" + node->element.value + L"\" not found in a map." });
				return;
			}

			auto structDecl = symbols->structDecls.Values()[index];
			auto fieldDecl = From(structDecl->members)
				.Where([&](auto&& member) { return member->name.value == node->keyField.value; })
				.First({});
			if (!fieldDecl)
			{
				errors.Add({ node->keyField.codeRange,L"Struct \"" + node->element.value + L"\" does not contain field " + node->keyField.value + L"\" required in a map." });
				return;
			}
		}

		void Visit(GuiRpMapType* node) override
		{
			node->element->Accept(this);
			node->keyType->Accept(this);
		}

		// GuiRpDeclaration::IVisitor

		bool EnsureTypeUndefined(const glr::ParsingToken& name)
		{
			if (symbols->enumDecls.Keys().Contains(name.value))
			{
				errors.Add({ name.codeRange,L"Enum \"" + name.value + L"\" already defined." });
				return false;
			}
			if (symbols->unionDecls.Keys().Contains(name.value))
			{
				errors.Add({ name.codeRange,L"Union \"" + name.value + L"\" already defined." });
				return false;
			}
			if (symbols->structDecls.Keys().Contains(name.value))
			{
				errors.Add({ name.codeRange,L"Struct \"" + name.value + L"\" already defined." });
				return false;
			}
			return true;
		}

		void Visit(GuiRpEnumDecl* node) override
		{
			if (!EnsureTypeUndefined(node->name)) return;

			SortedList<WString> memberNames;
			for (auto member : node->members)
			{
				if (memberNames.Contains(member->name.value))
				{
					errors.Add({ member->name.codeRange,L"Enum member \"" + node->name.value + L"::" + member->name.value + L"\" already exists." });
				}
				else
				{
					memberNames.Add(member->name.value);
				}
			}

			for (auto att : node->attributes)
			{
				if (att->name.value == L"@Cpp")
				{
					if (!att->cppType)
					{
						errors.Add({ att->name.codeRange,L"Missing parameter for attribute: \"" + att->name.value + L"\"." });
					}
					else if (symbols->cppMapping.Keys().Contains(node->name.value))
					{
						errors.Add({ att->name.codeRange,L"Too many attributes: \"" + att->name.value + L"\"." });
					}
					else
					{
						symbols->cppMapping.Add(node->name.value, att->cppType.value);
					}
				}
				else if (att->name.value == L"@CppNamespace")
				{
					if (!att->cppType)
					{
						errors.Add({ att->name.codeRange,L"Missing parameter for attribute: \"" + att->name.value + L"\"." });
					}
					else if (symbols->cppNamespaces.Keys().Contains(node->name.value))
					{
						errors.Add({ att->name.codeRange,L"Too many attributes: \"" + att->name.value + L"\"." });
					}
					else
					{
						symbols->cppNamespaces.Add(node->name.value, att->cppType.value);
					}
				}
				else
				{
					errors.Add({ att->name.codeRange,L"Unsupported attribute: \"" + att->name.value + L"\" on enum \"" + node->name.value + L"\"." });
				}
			}
			symbols->enumDecls.Add(node->name.value, node);
		}

		void Visit(GuiRpUnionDecl* node) override
		{
			if (!EnsureTypeUndefined(node->name)) return;

			SortedList<WString> memberNames;
			for (auto member : node->members)
			{
				if (memberNames.Contains(member->name.value))
				{
					errors.Add({ member->name.codeRange,L"Union member \"" + node->name.value + L"::" + member->name.value + L"\" already exists." });
				}
				else
				{
					memberNames.Add(member->name.value);

					vint index = symbols->structDecls.Keys().IndexOf(member->name.value);
					if (index == -1)
					{
						errors.Add({ member->name.codeRange,L"Struct \"" + member->name.value + L"\" not found in union " + node->name.value + L"\"." });
						return;
					}

					auto structDecl = symbols->structDecls.Values()[index];
					if (structDecl->type != GuiRpStructType::Struct)
					{
						errors.Add({ member->name.codeRange,L"Struct \"" + member->name.value + L"\" in union " + node->name.value + L"\" should not be a class." });
						return;
					}
				}
			}

			for (auto att : node->attributes)
			{
				errors.Add({ att->name.codeRange,L"Unsupported attribute: \"" + att->name.value + L"\" on union \"" + node->name.value + L"\"." });
			}
			symbols->unionDecls.Add(node->name.value, node);
		}

		void Visit(GuiRpStructDecl* node) override
		{
			if (!EnsureTypeUndefined(node->name)) return;
			if (node->type == GuiRpStructType::Class)
			{
				symbols->structDecls.Add(node->name.value, node);
			}

			SortedList<WString> memberNames;
			for (auto member : node->members)
			{
				if (memberNames.Contains(member->name.value))
				{
					errors.Add({ member->name.codeRange,L"Struct member \"" + node->name.value + L"::" + member->name.value + L"\" already exists." });
				}
				else
				{
					memberNames.Add(member->name.value);
				}
				member->type->Accept(this);
			}

			for (auto att : node->attributes)
			{
				if (att->name.value == L"@Cpp")
				{
					if (!att->cppType)
					{
						errors.Add({ att->name.codeRange,L"Missing parameter for attribute: \"" + att->name.value + L"\"." });
					}
					else if (symbols->cppMapping.Keys().Contains(node->name.value))
					{
						errors.Add({ att->name.codeRange,L"Too many attributes: \"" + att->name.value + L"\"." });
					}
					else
					{
						symbols->cppMapping.Add(node->name.value, att->cppType.value);
					}
				}
				else
				{
					errors.Add({ att->name.codeRange,L"Unsupported attribute: \"" + att->name.value + L"\" on struct \"" + node->name.value + L"\"." });
				}
			}

			if (node->type == GuiRpStructType::Struct)
			{
				symbols->structDecls.Add(node->name.value, node);
			}
		}

		void VisitDropAttribute(Ptr<remoteprotocol::GuiRpAttribute> att, const WString& name, SortedList<WString>& names)
		{
			if (names.Contains(name))
			{
				errors.Add({ att->name.codeRange,L"Too many attributes: \"" + att->name.value + L"\"." });
			}
			else
			{
				names.Add(name);
			}
		}

		void Visit(GuiRpMessageDecl* node) override
		{
			if (symbols->messageDecls.Keys().Contains(node->name.value))
			{
				errors.Add({ node->name.codeRange,L"Message \"" + node->name.value + L"\" already exists." });
				return;
			}

			if (node->request)
			{
				node->request->type->Accept(this);
			}

			if (node->response)
			{
				node->response->type->Accept(this);
			}

			for (auto att : node->attributes)
			{
				if (att->name.value == L"@DropRepeat")
				{
					if (node->response)
					{
						errors.Add({ node->name.codeRange,L"@DropRepeat cannot be used on message \"" + node->name.value + L"\" since it has response." });
					}
					VisitDropAttribute(att, node->name.value, symbols->dropRepeatDeclNames);
				}
				else
				{
					errors.Add({ att->name.codeRange,L"Unsupported attribute: \"" + att->name.value + L"\" on message \"" + node->name.value + L"\"." });
				}
			}
			symbols->messageDecls.Add(node->name.value, node);
		}

		void Visit(GuiRpEventDecl* node) override
		{
			if (symbols->eventDecls.Keys().Contains(node->name.value))
			{
				errors.Add({ node->name.codeRange,L"Event \"" + node->name.value + L"\" already exists." });
				return;
			}

			if (node->request)
			{
				node->request->type->Accept(this);
			}

			for (auto att : node->attributes)
			{
				if (att->name.value == L"@DropRepeat")
				{
					VisitDropAttribute(att, node->name.value, symbols->dropRepeatDeclNames);
				}
				else if (att->name.value == L"@DropConsecutive")
				{
					VisitDropAttribute(att, node->name.value, symbols->dropConsecutiveDeclNames);
				}
				else
				{
					errors.Add({ att->name.codeRange,L"Unsupported attribute: \"" + att->name.value + L"\" on event \"" + node->name.value + L"\"." });
				}
			}

			if (symbols->dropRepeatDeclNames.Contains(node->name.value) && symbols->dropConsecutiveDeclNames.Contains(node->name.value))
			{
				errors.Add({ node->name.codeRange,L"@DropRepeat and @DropConsecutive cannot be used together on event \"" + node->name.value + L"\"." });
			}
			symbols->eventDecls.Add(node->name.value, node);
		}
	};

	Ptr<GuiRpSymbols> CheckRemoteProtocolSchema(Ptr<GuiRpSchema> schema, collections::List<GuiRpError>& errors)
	{
		auto symbols = Ptr(new GuiRpSymbols);
		GuiRpCheckSchemaVisitor visitor(symbols, errors);
		for (auto decl : schema->declarations)
		{
			decl->Accept(&visitor);
		}
		return symbols;
	}

/***********************************************************************
GenerateRemoteProtocolHeaderFile
***********************************************************************/

	class GuiRpPrintTypeVisitor : public Object, public GuiRpType::IVisitor
	{
	protected:
		Ptr<GuiRpSymbols>			symbols;
		GuiRpCppConfig&				config;
		stream::TextWriter&			writer;

	public:
		GuiRpPrintTypeVisitor(Ptr<GuiRpSymbols> _symbols, GuiRpCppConfig& _config, stream::TextWriter& _writer)
			: symbols(_symbols)
			, config(_config)
			, writer(_writer)
		{
		}

		// GuiRpType::IVisitor

		void Visit(GuiRpPrimitiveType* node) override
		{
			switch (node->type)
			{
			case GuiRpPrimitiveTypes::Boolean:
				writer.WriteString(L"bool");
				break;
			case GuiRpPrimitiveTypes::Integer:
				writer.WriteString(L"::vl::vint");
				break;
			case GuiRpPrimitiveTypes::Float:
				writer.WriteString(L"float");
				break;
			case GuiRpPrimitiveTypes::Double:
				writer.WriteString(L"double");
				break;
			case GuiRpPrimitiveTypes::String:
				writer.WriteString(L"::vl::WString");
				break;
			case GuiRpPrimitiveTypes::Char:
				writer.WriteString(L"wchar_t");
				break;
			case GuiRpPrimitiveTypes::Key:
				writer.WriteString(L"::vl::presentation::VKEY");
				break;
			case GuiRpPrimitiveTypes::Color:
				writer.WriteString(L"::vl::presentation::Color");
				break;
			case GuiRpPrimitiveTypes::Binary:
				writer.WriteString(L"::vl::Ptr<::vl::stream::MemoryStream>");
				break;
			default:
				CHECK_FAIL(L"Unrecognized type");
			}
		}

		static WString GetCppType(const WString& type, Ptr<GuiRpSymbols> symbols, GuiRpCppConfig& config, bool forJson = false)
		{
			bool ptr = false;
			if (!forJson)
			{
				vint index = symbols->structDecls.Keys().IndexOf(type);
				if (index != -1)
				{
					auto structDecl = symbols->structDecls.Values()[index];
					ptr = structDecl->type == GuiRpStructType::Class;
				}
			}

			WString result;
			{
				vint index = symbols->cppMapping.Keys().IndexOf(type);
				if (index == -1)
				{
					result = L"::" + config.cppNamespace + L"::" + type;
				}
				else
				{
					result = symbols->cppMapping.Values()[index];
				}
			}

			if (ptr)
			{
				return L"::vl::Ptr<" + result + L">";
			}
			else
			{
				return result;
			}
		}

		static WString GetCppTypeForJson(const WString& type, Ptr<GuiRpSymbols> symbols, GuiRpCppConfig& config)
		{
			return GetCppType(type, symbols, config, true);
		}

		static WString GetCppNamespace(const WString& type, Ptr<GuiRpSymbols> symbols, GuiRpCppConfig& config)
		{
			vint index = symbols->cppNamespaces.Keys().IndexOf(type);
			if (index == -1)
			{
				return GetCppType(type, symbols, config);
			}
			else
			{
				return symbols->cppNamespaces.Values()[index];
			}
		}

		void Visit(GuiRpReferenceType* node) override
		{
			writer.WriteString(GetCppType(node->name.value, symbols, config));
		}

		void Visit(GuiRpOptionalType* node) override
		{
			writer.WriteString(L"::vl::Nullable<");
			node->element->Accept(this);
			writer.WriteString(L">");
		}

		void Visit(GuiRpArrayType* node) override
		{
			writer.WriteString(L"::vl::Ptr<::vl::collections::List<");
			node->element->Accept(this);
			writer.WriteString(L">>");
		}

		void Visit(GuiRpArrayMapType* node) override
		{
			auto cppName = GetCppType(node->element.value, symbols, config);
			auto structDecl = symbols->structDecls[node->element.value];
			auto fieldDecl = From(structDecl->members)
				.Where([&](auto&& member) { return member->name.value == node->keyField.value; })
				.First();
			writer.WriteString(L"::vl::Ptr<::vl::presentation::remoteprotocol::ArrayMap<");
			fieldDecl->type->Accept(this);
			writer.WriteString(L", ");
			writer.WriteString(cppName);
			writer.WriteString(L", &");
			writer.WriteString(cppName);
			writer.WriteString(L"::");
			writer.WriteString(node->keyField.value);
			writer.WriteString(L">>");
		}

		void Visit(GuiRpMapType* node) override
		{
			writer.WriteString(L"::vl::Ptr<::vl::collections::Dictionary<");
			node->keyType->Accept(this);
			writer.WriteString(L", ");
			node->element->Accept(this);
			writer.WriteString(L">>");
		}
	};

	void GenerateSerializerFunctionHeader(const WString& type, bool semicolon, stream::TextWriter& writer)
	{
		writer.WriteString(L"\ttemplate<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<" + type + L">(const " + type + L" & value)");
		writer.WriteLine(semicolon ? L";" : L"");
	}

	void GenerateDeserializerFunctionHeader(const WString& type, bool semicolon, stream::TextWriter& writer)
	{
		writer.WriteString(L"\ttemplate<> void ConvertJsonToCustomType<" + type + L">(vl::Ptr<vl::glr::json::JsonNode> node, " + type + L"& value)");
		writer.WriteLine(semicolon ? L";" : L"");
	}

	void GenerateRemoteProtocolHeaderFile(Ptr<GuiRpSchema> schema, Ptr<GuiRpSymbols> symbols, GuiRpCppConfig& config, stream::TextWriter& writer)
	{
		writer.WriteLine(L"/***********************************************************************");
		writer.WriteLine(L"This file is generated by : Vczh GacUI Remote Protocol Generator");
		writer.WriteLine(L"Licensed under https ://github.com/vczh-libraries/License");
		writer.WriteLine(L"***********************************************************************/");
		writer.WriteLine(L"");
		writer.WriteLine(L"#ifndef " + config.headerGuard);
		writer.WriteLine(L"#define " + config.headerGuard);
		writer.WriteLine(L"");
		writer.WriteLine(L"#include \"" + config.headerInclude + L"\"");
		writer.WriteLine(L"");

		auto structDecls = From(schema->declarations).FindType<GuiRpStructDecl>();

		writer.WriteLine(L"namespace " + config.cppNamespace);
		writer.WriteLine(L"{");
		for (auto structDecl : structDecls)
		{
			if (!symbols->cppMapping.Keys().Contains(structDecl->name.value))
			{
				writer.WriteLine(L"\tstruct " + structDecl->name.value + L";");
			}
		}
		writer.WriteLine(L"}");
		
		writer.WriteLine(L"namespace vl::presentation::remoteprotocol");
		writer.WriteLine(L"{");
		for (auto structDecl : structDecls)
		{
			WString cppName = GuiRpPrintTypeVisitor::GetCppType(structDecl->name.value, symbols, config);
			writer.WriteLine(L"\ttemplate<> struct JsonNameHelper<" + cppName + L"> { static constexpr const wchar_t* Name = L\"" + structDecl->name.value + L"\"; };");
		}
		writer.WriteLine(L"}");

		writer.WriteLine(L"namespace " + config.cppNamespace);
		writer.WriteLine(L"{");

		GuiRpPrintTypeVisitor printTypeVisitor(symbols, config, writer);

		for (auto enumDecl : From(schema->declarations).FindType<GuiRpEnumDecl>())
		{
			if (!symbols->cppMapping.Keys().Contains(enumDecl->name.value))
			{
				writer.WriteLine(L"\tenum class " + enumDecl->name.value);
				writer.WriteLine(L"\t{");
				for (auto member : enumDecl->members)
				{
					writer.WriteLine(L"\t\t" + member->name.value + L",");
				}
				writer.WriteLine(L"\t};");
				writer.WriteLine(L"");
			}
		}

		for (auto unionDecl : From(schema->declarations).FindType<GuiRpUnionDecl>())
		{
			if (!symbols->cppMapping.Keys().Contains(unionDecl->name.value))
			{
				writer.WriteLine(L"\tusing " + unionDecl->name.value + L" = ::vl::Variant<");
				for (auto [member, index] : indexed(unionDecl->members))
				{
					writer.WriteString(L"\t\t" + GuiRpPrintTypeVisitor::GetCppType(member->name.value, symbols, config));
					if (index < unionDecl->members.Count() - 1)
					{
						writer.WriteLine(L",");
					}
					else
					{
						writer.WriteLine(L"");
					}
				}
				writer.WriteLine(L"\t>;");
				writer.WriteLine(L"");
			}
		}

		for (auto structDecl : From(schema->declarations).FindType<GuiRpStructDecl>())
		{
			if (!symbols->cppMapping.Keys().Contains(structDecl->name.value))
			{
				writer.WriteLine(L"\tstruct " + structDecl->name.value);
				writer.WriteLine(L"\t{");
				for (auto member : structDecl->members)
				{
					writer.WriteString(L"\t\t");
					member->type->Accept(&printTypeVisitor);
					writer.WriteLine(L" " + member->name.value + L";");
				}
				writer.WriteLine(L"\t};");
				writer.WriteLine(L"");
			}
		}

		for (auto enumDecl : From(schema->declarations).FindType<GuiRpEnumDecl>())
		{
			GenerateSerializerFunctionHeader(GuiRpPrintTypeVisitor::GetCppType(enumDecl->name.value, symbols, config), true, writer);
		}
		for (auto structDecl : From(schema->declarations).FindType<GuiRpStructDecl>())
		{
			GenerateSerializerFunctionHeader(GuiRpPrintTypeVisitor::GetCppTypeForJson(structDecl->name.value, symbols, config), true, writer);
		}
		writer.WriteLine(L"");

		for (auto enumDecl : From(schema->declarations).FindType<GuiRpEnumDecl>())
		{
			GenerateDeserializerFunctionHeader(GuiRpPrintTypeVisitor::GetCppType(enumDecl->name.value, symbols, config), true, writer);
		}
		for (auto structDecl : From(schema->declarations).FindType<GuiRpStructDecl>())
		{
			GenerateDeserializerFunctionHeader(GuiRpPrintTypeVisitor::GetCppTypeForJson(structDecl->name.value, symbols, config), true, writer);
		}
		writer.WriteLine(L"");

		writer.WriteLine(L"#define " + config.builderMacroPrefix + L"_MESSAGES(HANDLER)\\");
		for (auto messageDecl : From(schema->declarations).FindType<GuiRpMessageDecl>())
		{
			writer.WriteString(L"\tHANDLER(" + messageDecl->name.value);

			writer.WriteString(L", ");
			if (messageDecl->request)
			{
				messageDecl->request->type->Accept(&printTypeVisitor);
			}
			else
			{
				writer.WriteString(L"void");
			}

			writer.WriteString(L", ");
			if (messageDecl->response)
			{
				messageDecl->response->type->Accept(&printTypeVisitor);
			}
			else
			{
				writer.WriteString(L"void");
			}

			writer.WriteString(messageDecl->request ? L", REQ" : L", NOREQ");
			writer.WriteString(messageDecl->response ? L", RES" : L", NORES");
			writer.WriteString(symbols->dropRepeatDeclNames.Contains(messageDecl->name.value) ? L", DROPREP" : L", NODROP");
			writer.WriteLine(L")\\");
		}
		writer.WriteLine(L"");

		writer.WriteLine(L"#define " + config.builderMacroPrefix + L"_EVENTS(HANDLER)\\");
		for (auto eventDecl : From(schema->declarations).FindType<GuiRpEventDecl>())
		{
			writer.WriteString(L"\tHANDLER(" + eventDecl->name.value);

			writer.WriteString(L", ");
			if (eventDecl->request)
			{
				eventDecl->request->type->Accept(&printTypeVisitor);
			}
			else
			{
				writer.WriteString(L"void");
			}

			writer.WriteString(eventDecl->request ? L", REQ" : L", NOREQ");
			writer.WriteString(
				symbols->dropRepeatDeclNames.Contains(eventDecl->name.value) ? L", DROPREP" :
				symbols->dropConsecutiveDeclNames.Contains(eventDecl->name.value) ? L", DROPCON" :
				L", NODROP");
			writer.WriteLine(L")\\");
		}
		writer.WriteLine(L"");

		SortedList<WString> requestTypes, responseTypes, eventTypes;
		{
			for (auto messageDecl : From(schema->declarations).FindType<GuiRpMessageDecl>())
			{
				if (messageDecl->request)
				{
					auto type = stream::GenerateToStream([&](stream::TextWriter& writer)
					{
						GuiRpPrintTypeVisitor visitor(symbols, config, writer);
						messageDecl->request->type->Accept(&visitor);
					});
					if (!requestTypes.Contains(type))
					{
						requestTypes.Add(type);
					}
				}

				if (messageDecl->response)
				{
					auto type = stream::GenerateToStream([&](stream::TextWriter& writer)
					{
						GuiRpPrintTypeVisitor visitor(symbols, config, writer);
						messageDecl->response->type->Accept(&visitor);
					});
					if (!responseTypes.Contains(type))
					{
						responseTypes.Add(type);
					}
				}
			}

			for (auto eventDecl : From(schema->declarations).FindType<GuiRpEventDecl>())
			{
				if (eventDecl->request)
				{
					auto type = stream::GenerateToStream([&](stream::TextWriter& writer)
					{
						GuiRpPrintTypeVisitor visitor(symbols, config, writer);
						eventDecl->request->type->Accept(&visitor);
					});
					if (!eventTypes.Contains(type))
					{
						eventTypes.Add(type);
					}
				}
			}
		}

		writer.WriteLine(L"#define GACUI_REMOTEPROTOCOL_MESSAGE_REQUEST_TYPES(HANDLER)\\");
		for (auto type : requestTypes) writer.WriteLine(L"\tHANDLER(" + type + L")\\");
		writer.WriteLine(L"");

		writer.WriteLine(L"#define GACUI_REMOTEPROTOCOL_MESSAGE_RESPONSE_TYPES(HANDLER)\\");
		for (auto type : responseTypes) writer.WriteLine(L"\tHANDLER(" + type + L")\\");
		writer.WriteLine(L"");

		writer.WriteLine(L"#define GACUI_REMOTEPROTOCOL_EVENT_REQUEST_TYPES(HANDLER)\\");
		for (auto type : eventTypes) writer.WriteLine(L"\tHANDLER(" + type + L")\\");
		writer.WriteLine(L"");

		writer.WriteLine(L"}");
		writer.WriteLine(L"");
		writer.WriteLine(L"#endif");
	}

/***********************************************************************
GenerateRemoteProtocolCppFile
***********************************************************************/

	void GenerateEnumSerializerFunctionImpl(Ptr<GuiRpEnumDecl> enumDecl, Ptr<GuiRpSymbols> symbols, GuiRpCppConfig& config, stream::TextWriter& writer)
	{
		WString cppName = GuiRpPrintTypeVisitor::GetCppType(enumDecl->name.value, symbols, config);
		WString cppNss = GuiRpPrintTypeVisitor::GetCppNamespace(enumDecl->name.value, symbols, config);
		GenerateSerializerFunctionHeader(cppName, false, writer);
		writer.WriteLine(L"\t{");
		writer.WriteLine(L"#define ERROR_MESSAGE_PREFIX L\"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<" + cppName + L">(const " + cppName + L"&)#\"");
		writer.WriteLine(L"\t\tauto node = Ptr(new glr::json::JsonString);");
		writer.WriteLine(L"\t\tswitch (value)");
		writer.WriteLine(L"\t\t{");
		for (auto member : enumDecl->members)
		{
			writer.WriteLine(L"\t\tcase " + cppNss + L"::" + member->name.value + L": node->content.value = WString::Unmanaged(L\"" + member->name.value + L"\"); break;");
		}
		writer.WriteLine(L"\t\tdefault: CHECK_FAIL(ERROR_MESSAGE_PREFIX L\"Unsupported enum value.\");");
		writer.WriteLine(L"\t\t}");
		writer.WriteLine(L"\t\treturn node;");
		writer.WriteLine(L"#undef ERROR_MESSAGE_PREFIX");
		writer.WriteLine(L"\t}");
		writer.WriteLine(L"");
	}

	void GenerateStructSerializerFunctionImpl(Ptr<GuiRpStructDecl> structDecl, Ptr<GuiRpSymbols> symbols, GuiRpCppConfig& config, stream::TextWriter& writer)
	{
		WString cppName = GuiRpPrintTypeVisitor::GetCppTypeForJson(structDecl->name.value, symbols, config);
		GenerateSerializerFunctionHeader(cppName, false, writer);
		writer.WriteLine(L"\t{");
		writer.WriteLine(L"\t\tauto node = Ptr(new glr::json::JsonObject);");
		for (auto member : structDecl->members)
		{
			writer.WriteLine(L"\t\tConvertCustomTypeToJsonField(node, L\"" + member->name.value + L"\", value." + member->name.value + L");");
		}
		writer.WriteLine(L"\t\treturn node;");
		writer.WriteLine(L"\t}");
		writer.WriteLine(L"");
	}

	void GenerateEnumDeserializerFunctionImpl(Ptr<GuiRpEnumDecl> enumDecl, Ptr<GuiRpSymbols> symbols, GuiRpCppConfig& config, stream::TextWriter& writer)
	{
		WString cppName = GuiRpPrintTypeVisitor::GetCppType(enumDecl->name.value, symbols, config);
		WString cppNss = GuiRpPrintTypeVisitor::GetCppNamespace(enumDecl->name.value, symbols, config);
		GenerateDeserializerFunctionHeader(cppName, false, writer);
		writer.WriteLine(L"\t{");
		writer.WriteLine(L"#define ERROR_MESSAGE_PREFIX L\"vl::presentation::remoteprotocol::ConvertJsonToCustomType<" + cppName + L">(Ptr<JsonNode>, " + cppName + L"&)#\"");
		writer.WriteLine(L"\t\tauto jsonNode = node.Cast<glr::json::JsonString>();");
		writer.WriteLine(L"\t\tCHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L\"Json node does not match the expected type.\");");
		for (auto member : enumDecl->members)
		{
			writer.WriteLine(L"\t\tif (jsonNode->content.value == L\"" + member->name.value + L"\") value = " + cppNss + L"::" + member->name.value + L"; else");
		}
		writer.WriteLine(L"\t\tCHECK_FAIL(ERROR_MESSAGE_PREFIX L\"Unsupported enum value.\");");
		writer.WriteLine(L"#undef ERROR_MESSAGE_PREFIX");
		writer.WriteLine(L"\t}");
		writer.WriteLine(L"");
	}

	void GenerateStructDeserializerFunctionImpl(Ptr<GuiRpStructDecl> structDecl, Ptr<GuiRpSymbols> symbols, GuiRpCppConfig& config, stream::TextWriter& writer)
	{
		WString cppName = GuiRpPrintTypeVisitor::GetCppTypeForJson(structDecl->name.value, symbols, config);
		GenerateDeserializerFunctionHeader(cppName, false, writer);
		writer.WriteLine(L"\t{");
		writer.WriteLine(L"#define ERROR_MESSAGE_PREFIX L\"vl::presentation::remoteprotocol::ConvertJsonToCustomType<" + cppName + L">(Ptr<JsonNode>, " + cppName + L"&)#\"");
		writer.WriteLine(L"\t\tauto jsonNode = node.Cast<glr::json::JsonObject>();");
		writer.WriteLine(L"\t\tCHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L\"Json node does not match the expected type.\");");
		writer.WriteLine(L"\t\tfor (auto field : jsonNode->fields)");
		writer.WriteLine(L"\t\t{");
		for (auto member : structDecl->members)
		{
			writer.WriteLine(L"\t\t\tif (field->name.value == L\"" + member->name.value + L"\") ConvertJsonToCustomType(field->value, value." + member->name.value + L"); else");
		}
		writer.WriteLine(L"\t\t\tCHECK_FAIL(ERROR_MESSAGE_PREFIX L\"Unsupported struct member.\");");
		writer.WriteLine(L"\t\t}");
		writer.WriteLine(L"#undef ERROR_MESSAGE_PREFIX");
		writer.WriteLine(L"\t}");
		writer.WriteLine(L"");
	}

	void GenerateRemoteProtocolCppFile(Ptr<GuiRpSchema> schema, Ptr<GuiRpSymbols> symbols, GuiRpCppConfig& config, stream::TextWriter& writer)
	{
		writer.WriteLine(L"/***********************************************************************");
		writer.WriteLine(L"This file is generated by : Vczh GacUI Remote Protocol Generator");
		writer.WriteLine(L"Licensed under https ://github.com/vczh-libraries/License");
		writer.WriteLine(L"***********************************************************************/");
		writer.WriteLine(L"");
		writer.WriteLine(L"#include \"" + config.headerFileName + L"\"");
		writer.WriteLine(L"");
		writer.WriteLine(L"namespace " + config.cppNamespace);
		writer.WriteLine(L"{");

		for (auto enumDecl : From(schema->declarations).FindType<GuiRpEnumDecl>())
		{
			GenerateEnumSerializerFunctionImpl(enumDecl, symbols, config, writer);
		}
		for (auto structDecl : From(schema->declarations).FindType<GuiRpStructDecl>())
		{
			GenerateStructSerializerFunctionImpl(structDecl, symbols, config, writer);
		}

		for (auto enumDecl : From(schema->declarations).FindType<GuiRpEnumDecl>())
		{
			GenerateEnumDeserializerFunctionImpl(enumDecl, symbols, config, writer);
		}
		for (auto structDecl : From(schema->declarations).FindType<GuiRpStructDecl>())
		{
			GenerateStructDeserializerFunctionImpl(structDecl, symbols, config, writer);
		}
		writer.WriteLine(L"}");
	}
}


/***********************************************************************
.\REMOTEPROTOCOL\GENERATED\GUIREMOTEPROTOCOLAST.CPP
***********************************************************************/
/***********************************************************************
This file is generated by: Vczh Parser Generator
From parser definition:Ast
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/


namespace vl::presentation::remoteprotocol
{
/***********************************************************************
Visitor Pattern Implementation
***********************************************************************/

	void GuiRpPrimitiveType::Accept(GuiRpType::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiRpReferenceType::Accept(GuiRpType::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiRpOptionalType::Accept(GuiRpType::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiRpArrayType::Accept(GuiRpType::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiRpArrayMapType::Accept(GuiRpType::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiRpMapType::Accept(GuiRpType::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiRpEnumDecl::Accept(GuiRpDeclaration::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiRpUnionDecl::Accept(GuiRpDeclaration::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiRpStructDecl::Accept(GuiRpDeclaration::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiRpMessageDecl::Accept(GuiRpDeclaration::IVisitor* visitor)
	{
		visitor->Visit(this);
	}

	void GuiRpEventDecl::Accept(GuiRpDeclaration::IVisitor* visitor)
	{
		visitor->Visit(this);
	}
}
namespace vl::reflection::description
{
#ifndef VCZH_DEBUG_NO_REFLECTION

	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpType, presentation::remoteprotocol::GuiRpType)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpType::IVisitor, presentation::remoteprotocol::GuiRpType::IVisitor)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpPrimitiveTypes, presentation::remoteprotocol::GuiRpPrimitiveTypes)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpPrimitiveType, presentation::remoteprotocol::GuiRpPrimitiveType)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpReferenceType, presentation::remoteprotocol::GuiRpReferenceType)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpOptionalType, presentation::remoteprotocol::GuiRpOptionalType)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpArrayType, presentation::remoteprotocol::GuiRpArrayType)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpArrayMapType, presentation::remoteprotocol::GuiRpArrayMapType)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpMapType, presentation::remoteprotocol::GuiRpMapType)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpAttribute, presentation::remoteprotocol::GuiRpAttribute)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpDeclaration, presentation::remoteprotocol::GuiRpDeclaration)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpDeclaration::IVisitor, presentation::remoteprotocol::GuiRpDeclaration::IVisitor)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpEnumMember, presentation::remoteprotocol::GuiRpEnumMember)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpEnumDecl, presentation::remoteprotocol::GuiRpEnumDecl)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpUnionMember, presentation::remoteprotocol::GuiRpUnionMember)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpUnionDecl, presentation::remoteprotocol::GuiRpUnionDecl)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpStructMember, presentation::remoteprotocol::GuiRpStructMember)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpStructType, presentation::remoteprotocol::GuiRpStructType)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpStructDecl, presentation::remoteprotocol::GuiRpStructDecl)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpMessageRequest, presentation::remoteprotocol::GuiRpMessageRequest)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpMessageResponse, presentation::remoteprotocol::GuiRpMessageResponse)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpMessageDecl, presentation::remoteprotocol::GuiRpMessageDecl)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpEventRequest, presentation::remoteprotocol::GuiRpEventRequest)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpEventDecl, presentation::remoteprotocol::GuiRpEventDecl)
	IMPL_TYPE_INFO_RENAME(vl::presentation::remoteprotocol::GuiRpSchema, presentation::remoteprotocol::GuiRpSchema)

#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpType)
		CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)

	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpType)

	BEGIN_ENUM_ITEM(vl::presentation::remoteprotocol::GuiRpPrimitiveTypes)
		ENUM_ITEM_NAMESPACE(vl::presentation::remoteprotocol::GuiRpPrimitiveTypes)
		ENUM_NAMESPACE_ITEM(Boolean)
		ENUM_NAMESPACE_ITEM(Integer)
		ENUM_NAMESPACE_ITEM(Float)
		ENUM_NAMESPACE_ITEM(Double)
		ENUM_NAMESPACE_ITEM(String)
		ENUM_NAMESPACE_ITEM(Char)
		ENUM_NAMESPACE_ITEM(Key)
		ENUM_NAMESPACE_ITEM(Color)
		ENUM_NAMESPACE_ITEM(Binary)
	END_ENUM_ITEM(vl::presentation::remoteprotocol::GuiRpPrimitiveTypes)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpPrimitiveType)
		CLASS_MEMBER_BASE(vl::presentation::remoteprotocol::GuiRpType)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpPrimitiveType>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(type)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpPrimitiveType)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpReferenceType)
		CLASS_MEMBER_BASE(vl::presentation::remoteprotocol::GuiRpType)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpReferenceType>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(name)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpReferenceType)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpOptionalType)
		CLASS_MEMBER_BASE(vl::presentation::remoteprotocol::GuiRpType)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpOptionalType>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(element)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpOptionalType)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpArrayType)
		CLASS_MEMBER_BASE(vl::presentation::remoteprotocol::GuiRpType)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpArrayType>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(element)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpArrayType)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpArrayMapType)
		CLASS_MEMBER_BASE(vl::presentation::remoteprotocol::GuiRpType)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpArrayMapType>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(element)
		CLASS_MEMBER_FIELD(keyField)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpArrayMapType)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpMapType)
		CLASS_MEMBER_BASE(vl::presentation::remoteprotocol::GuiRpType)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpMapType>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(element)
		CLASS_MEMBER_FIELD(keyType)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpMapType)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpAttribute)
		CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpAttribute>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(name)
		CLASS_MEMBER_FIELD(cppType)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpAttribute)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpDeclaration)
		CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)

		CLASS_MEMBER_FIELD(attributes)
		CLASS_MEMBER_FIELD(name)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpDeclaration)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpEnumMember)
		CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpEnumMember>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(name)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpEnumMember)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpEnumDecl)
		CLASS_MEMBER_BASE(vl::presentation::remoteprotocol::GuiRpDeclaration)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpEnumDecl>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(members)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpEnumDecl)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpUnionMember)
		CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpUnionMember>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(name)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpUnionMember)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpUnionDecl)
		CLASS_MEMBER_BASE(vl::presentation::remoteprotocol::GuiRpDeclaration)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpUnionDecl>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(members)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpUnionDecl)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpStructMember)
		CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpStructMember>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(name)
		CLASS_MEMBER_FIELD(type)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpStructMember)

	BEGIN_ENUM_ITEM(vl::presentation::remoteprotocol::GuiRpStructType)
		ENUM_ITEM_NAMESPACE(vl::presentation::remoteprotocol::GuiRpStructType)
		ENUM_NAMESPACE_ITEM(Struct)
		ENUM_NAMESPACE_ITEM(Class)
	END_ENUM_ITEM(vl::presentation::remoteprotocol::GuiRpStructType)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpStructDecl)
		CLASS_MEMBER_BASE(vl::presentation::remoteprotocol::GuiRpDeclaration)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpStructDecl>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(type)
		CLASS_MEMBER_FIELD(members)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpStructDecl)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpMessageRequest)
		CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpMessageRequest>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(type)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpMessageRequest)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpMessageResponse)
		CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpMessageResponse>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(type)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpMessageResponse)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpMessageDecl)
		CLASS_MEMBER_BASE(vl::presentation::remoteprotocol::GuiRpDeclaration)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpMessageDecl>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(request)
		CLASS_MEMBER_FIELD(response)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpMessageDecl)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpEventRequest)
		CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpEventRequest>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(type)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpEventRequest)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpEventDecl)
		CLASS_MEMBER_BASE(vl::presentation::remoteprotocol::GuiRpDeclaration)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpEventDecl>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(request)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpEventDecl)

	BEGIN_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpSchema)
		CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)

		CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::presentation::remoteprotocol::GuiRpSchema>(), NO_PARAMETER)

		CLASS_MEMBER_FIELD(declarations)
	END_CLASS_MEMBER(vl::presentation::remoteprotocol::GuiRpSchema)

	BEGIN_INTERFACE_MEMBER(vl::presentation::remoteprotocol::GuiRpType::IVisitor)
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::remoteprotocol::GuiRpType::IVisitor::*)(vl::presentation::remoteprotocol::GuiRpPrimitiveType* node))
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::remoteprotocol::GuiRpType::IVisitor::*)(vl::presentation::remoteprotocol::GuiRpReferenceType* node))
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::remoteprotocol::GuiRpType::IVisitor::*)(vl::presentation::remoteprotocol::GuiRpOptionalType* node))
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::remoteprotocol::GuiRpType::IVisitor::*)(vl::presentation::remoteprotocol::GuiRpArrayType* node))
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::remoteprotocol::GuiRpType::IVisitor::*)(vl::presentation::remoteprotocol::GuiRpArrayMapType* node))
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::remoteprotocol::GuiRpType::IVisitor::*)(vl::presentation::remoteprotocol::GuiRpMapType* node))
	END_INTERFACE_MEMBER(vl::presentation::remoteprotocol::GuiRpType)

	BEGIN_INTERFACE_MEMBER(vl::presentation::remoteprotocol::GuiRpDeclaration::IVisitor)
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::remoteprotocol::GuiRpDeclaration::IVisitor::*)(vl::presentation::remoteprotocol::GuiRpEnumDecl* node))
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::remoteprotocol::GuiRpDeclaration::IVisitor::*)(vl::presentation::remoteprotocol::GuiRpUnionDecl* node))
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::remoteprotocol::GuiRpDeclaration::IVisitor::*)(vl::presentation::remoteprotocol::GuiRpStructDecl* node))
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::remoteprotocol::GuiRpDeclaration::IVisitor::*)(vl::presentation::remoteprotocol::GuiRpMessageDecl* node))
		CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::presentation::remoteprotocol::GuiRpDeclaration::IVisitor::*)(vl::presentation::remoteprotocol::GuiRpEventDecl* node))
	END_INTERFACE_MEMBER(vl::presentation::remoteprotocol::GuiRpDeclaration)

#endif

#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
	class GuiRemoteProtocolAstTypeLoader : public vl::Object, public ITypeLoader
	{
	public:
		void Load(ITypeManager* manager)
		{
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpType)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpType::IVisitor)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpPrimitiveTypes)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpPrimitiveType)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpReferenceType)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpOptionalType)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpArrayType)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpArrayMapType)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpMapType)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpAttribute)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpDeclaration)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpDeclaration::IVisitor)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpEnumMember)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpEnumDecl)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpUnionMember)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpUnionDecl)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpStructMember)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpStructType)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpStructDecl)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpMessageRequest)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpMessageResponse)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpMessageDecl)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpEventRequest)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpEventDecl)
			ADD_TYPE_INFO(vl::presentation::remoteprotocol::GuiRpSchema)
		}

		void Unload(ITypeManager* manager)
		{
		}
	};
#endif
#endif

	bool GuiRemoteProtocolAstLoadTypes()
	{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
		if (auto manager = GetGlobalTypeManager())
		{
			auto loader = Ptr(new GuiRemoteProtocolAstTypeLoader);
			return manager->AddTypeLoader(loader);
		}
#endif
		return false;
	}
}


/***********************************************************************
.\REMOTEPROTOCOL\GENERATED\GUIREMOTEPROTOCOLAST_JSON.CPP
***********************************************************************/
/***********************************************************************
This file is generated by: Vczh Parser Generator
From parser definition:Ast
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/


namespace vl::presentation::remoteprotocol::json_visitor
{
	void AstVisitor::PrintFields(GuiRpArrayMapType* node)
	{
		BeginField(vl::WString::Unmanaged(L"element"));
		WriteToken(node->element);
		EndField();
		BeginField(vl::WString::Unmanaged(L"keyField"));
		WriteToken(node->keyField);
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpArrayType* node)
	{
		BeginField(vl::WString::Unmanaged(L"element"));
		Print(node->element.Obj());
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpAttribute* node)
	{
		BeginField(vl::WString::Unmanaged(L"cppType"));
		WriteToken(node->cppType);
		EndField();
		BeginField(vl::WString::Unmanaged(L"name"));
		WriteToken(node->name);
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpDeclaration* node)
	{
		BeginField(vl::WString::Unmanaged(L"attributes"));
		BeginArray();
		for (auto&& listItem : node->attributes)
		{
			BeginArrayItem();
			Print(listItem.Obj());
			EndArrayItem();
		}
		EndArray();
		EndField();
		BeginField(vl::WString::Unmanaged(L"name"));
		WriteToken(node->name);
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpEnumDecl* node)
	{
		BeginField(vl::WString::Unmanaged(L"members"));
		BeginArray();
		for (auto&& listItem : node->members)
		{
			BeginArrayItem();
			Print(listItem.Obj());
			EndArrayItem();
		}
		EndArray();
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpEnumMember* node)
	{
		BeginField(vl::WString::Unmanaged(L"name"));
		WriteToken(node->name);
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpEventDecl* node)
	{
		BeginField(vl::WString::Unmanaged(L"request"));
		Print(node->request.Obj());
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpEventRequest* node)
	{
		BeginField(vl::WString::Unmanaged(L"type"));
		Print(node->type.Obj());
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpMapType* node)
	{
		BeginField(vl::WString::Unmanaged(L"element"));
		Print(node->element.Obj());
		EndField();
		BeginField(vl::WString::Unmanaged(L"keyType"));
		Print(node->keyType.Obj());
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpMessageDecl* node)
	{
		BeginField(vl::WString::Unmanaged(L"request"));
		Print(node->request.Obj());
		EndField();
		BeginField(vl::WString::Unmanaged(L"response"));
		Print(node->response.Obj());
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpMessageRequest* node)
	{
		BeginField(vl::WString::Unmanaged(L"type"));
		Print(node->type.Obj());
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpMessageResponse* node)
	{
		BeginField(vl::WString::Unmanaged(L"type"));
		Print(node->type.Obj());
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpOptionalType* node)
	{
		BeginField(vl::WString::Unmanaged(L"element"));
		Print(node->element.Obj());
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpPrimitiveType* node)
	{
		BeginField(vl::WString::Unmanaged(L"type"));
		switch (node->type)
		{
		case vl::presentation::remoteprotocol::GuiRpPrimitiveTypes::Binary:
			WriteString(vl::WString::Unmanaged(L"Binary"));
			break;
		case vl::presentation::remoteprotocol::GuiRpPrimitiveTypes::Boolean:
			WriteString(vl::WString::Unmanaged(L"Boolean"));
			break;
		case vl::presentation::remoteprotocol::GuiRpPrimitiveTypes::Char:
			WriteString(vl::WString::Unmanaged(L"Char"));
			break;
		case vl::presentation::remoteprotocol::GuiRpPrimitiveTypes::Color:
			WriteString(vl::WString::Unmanaged(L"Color"));
			break;
		case vl::presentation::remoteprotocol::GuiRpPrimitiveTypes::Double:
			WriteString(vl::WString::Unmanaged(L"Double"));
			break;
		case vl::presentation::remoteprotocol::GuiRpPrimitiveTypes::Float:
			WriteString(vl::WString::Unmanaged(L"Float"));
			break;
		case vl::presentation::remoteprotocol::GuiRpPrimitiveTypes::Integer:
			WriteString(vl::WString::Unmanaged(L"Integer"));
			break;
		case vl::presentation::remoteprotocol::GuiRpPrimitiveTypes::Key:
			WriteString(vl::WString::Unmanaged(L"Key"));
			break;
		case vl::presentation::remoteprotocol::GuiRpPrimitiveTypes::String:
			WriteString(vl::WString::Unmanaged(L"String"));
			break;
		default:
			WriteNull();
		}
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpReferenceType* node)
	{
		BeginField(vl::WString::Unmanaged(L"name"));
		WriteToken(node->name);
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpSchema* node)
	{
		BeginField(vl::WString::Unmanaged(L"declarations"));
		BeginArray();
		for (auto&& listItem : node->declarations)
		{
			BeginArrayItem();
			Print(listItem.Obj());
			EndArrayItem();
		}
		EndArray();
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpStructDecl* node)
	{
		BeginField(vl::WString::Unmanaged(L"members"));
		BeginArray();
		for (auto&& listItem : node->members)
		{
			BeginArrayItem();
			Print(listItem.Obj());
			EndArrayItem();
		}
		EndArray();
		EndField();
		BeginField(vl::WString::Unmanaged(L"type"));
		switch (node->type)
		{
		case vl::presentation::remoteprotocol::GuiRpStructType::Class:
			WriteString(vl::WString::Unmanaged(L"Class"));
			break;
		case vl::presentation::remoteprotocol::GuiRpStructType::Struct:
			WriteString(vl::WString::Unmanaged(L"Struct"));
			break;
		default:
			WriteNull();
		}
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpStructMember* node)
	{
		BeginField(vl::WString::Unmanaged(L"name"));
		WriteToken(node->name);
		EndField();
		BeginField(vl::WString::Unmanaged(L"type"));
		Print(node->type.Obj());
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpType* node)
	{
	}
	void AstVisitor::PrintFields(GuiRpUnionDecl* node)
	{
		BeginField(vl::WString::Unmanaged(L"members"));
		BeginArray();
		for (auto&& listItem : node->members)
		{
			BeginArrayItem();
			Print(listItem.Obj());
			EndArrayItem();
		}
		EndArray();
		EndField();
	}
	void AstVisitor::PrintFields(GuiRpUnionMember* node)
	{
		BeginField(vl::WString::Unmanaged(L"name"));
		WriteToken(node->name);
		EndField();
	}

	void AstVisitor::Visit(GuiRpPrimitiveType* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"PrimitiveType"), node);
		PrintFields(static_cast<GuiRpType*>(node));
		PrintFields(static_cast<GuiRpPrimitiveType*>(node));
		EndObject();
	}

	void AstVisitor::Visit(GuiRpReferenceType* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"ReferenceType"), node);
		PrintFields(static_cast<GuiRpType*>(node));
		PrintFields(static_cast<GuiRpReferenceType*>(node));
		EndObject();
	}

	void AstVisitor::Visit(GuiRpOptionalType* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"OptionalType"), node);
		PrintFields(static_cast<GuiRpType*>(node));
		PrintFields(static_cast<GuiRpOptionalType*>(node));
		EndObject();
	}

	void AstVisitor::Visit(GuiRpArrayType* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"ArrayType"), node);
		PrintFields(static_cast<GuiRpType*>(node));
		PrintFields(static_cast<GuiRpArrayType*>(node));
		EndObject();
	}

	void AstVisitor::Visit(GuiRpArrayMapType* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"ArrayMapType"), node);
		PrintFields(static_cast<GuiRpType*>(node));
		PrintFields(static_cast<GuiRpArrayMapType*>(node));
		EndObject();
	}

	void AstVisitor::Visit(GuiRpMapType* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"MapType"), node);
		PrintFields(static_cast<GuiRpType*>(node));
		PrintFields(static_cast<GuiRpMapType*>(node));
		EndObject();
	}

	void AstVisitor::Visit(GuiRpEnumDecl* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"EnumDecl"), node);
		PrintFields(static_cast<GuiRpDeclaration*>(node));
		PrintFields(static_cast<GuiRpEnumDecl*>(node));
		EndObject();
	}

	void AstVisitor::Visit(GuiRpUnionDecl* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"UnionDecl"), node);
		PrintFields(static_cast<GuiRpDeclaration*>(node));
		PrintFields(static_cast<GuiRpUnionDecl*>(node));
		EndObject();
	}

	void AstVisitor::Visit(GuiRpStructDecl* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"StructDecl"), node);
		PrintFields(static_cast<GuiRpDeclaration*>(node));
		PrintFields(static_cast<GuiRpStructDecl*>(node));
		EndObject();
	}

	void AstVisitor::Visit(GuiRpMessageDecl* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"MessageDecl"), node);
		PrintFields(static_cast<GuiRpDeclaration*>(node));
		PrintFields(static_cast<GuiRpMessageDecl*>(node));
		EndObject();
	}

	void AstVisitor::Visit(GuiRpEventDecl* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"EventDecl"), node);
		PrintFields(static_cast<GuiRpDeclaration*>(node));
		PrintFields(static_cast<GuiRpEventDecl*>(node));
		EndObject();
	}

	AstVisitor::AstVisitor(vl::stream::StreamWriter& _writer)
		: vl::glr::JsonVisitorBase(_writer)
	{
	}

	void AstVisitor::Print(GuiRpType* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		node->Accept(static_cast<GuiRpType::IVisitor*>(this));
	}

	void AstVisitor::Print(GuiRpDeclaration* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		node->Accept(static_cast<GuiRpDeclaration::IVisitor*>(this));
	}

	void AstVisitor::Print(GuiRpAttribute* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"Attribute"), node);
		PrintFields(static_cast<GuiRpAttribute*>(node));
		EndObject();
	}

	void AstVisitor::Print(GuiRpEnumMember* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"EnumMember"), node);
		PrintFields(static_cast<GuiRpEnumMember*>(node));
		EndObject();
	}

	void AstVisitor::Print(GuiRpUnionMember* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"UnionMember"), node);
		PrintFields(static_cast<GuiRpUnionMember*>(node));
		EndObject();
	}

	void AstVisitor::Print(GuiRpStructMember* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"StructMember"), node);
		PrintFields(static_cast<GuiRpStructMember*>(node));
		EndObject();
	}

	void AstVisitor::Print(GuiRpMessageRequest* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"MessageRequest"), node);
		PrintFields(static_cast<GuiRpMessageRequest*>(node));
		EndObject();
	}

	void AstVisitor::Print(GuiRpMessageResponse* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"MessageResponse"), node);
		PrintFields(static_cast<GuiRpMessageResponse*>(node));
		EndObject();
	}

	void AstVisitor::Print(GuiRpEventRequest* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"EventRequest"), node);
		PrintFields(static_cast<GuiRpEventRequest*>(node));
		EndObject();
	}

	void AstVisitor::Print(GuiRpSchema* node)
	{
		if (!node)
		{
			WriteNull();
			return;
		}
		BeginObject();
		WriteType(vl::WString::Unmanaged(L"Schema"), node);
		PrintFields(static_cast<GuiRpSchema*>(node));
		EndObject();
	}

}


/***********************************************************************
.\REMOTEPROTOCOL\GENERATED\GUIREMOTEPROTOCOLPARSER.CPP
***********************************************************************/
/***********************************************************************
This file is generated by: Vczh Parser Generator
From parser definition:GuiRemoteProtocol
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/


namespace vl::presentation::remoteprotocol
{
	void GuiRemoteProtocolParserData(vl::stream::IStream& outputStream)
	{
		static const vl::vint dataLength = 7660; // 109122 bytes before compressing
		static const vl::vint dataBlock = 256;
		static const vl::vint dataRemain = 236;
		static const vl::vint dataSolidRows = 29;
		static const vl::vint dataRows = 30;
		static const char* compressed[] = {
			"\x42\xAA\x01\x00\xE4\x1D\x00\x00\x21\x00\x01\x82\x80\x02\x0B\x82\x81\x82\x06\x89\x82\x9F\x7C\x85\x84\x87\x0C\x0A\x80\x89\x85\x1A\x84\x16\x84\x18\x0A\xB7\x0A\x9E\x1A\x84\x22\x84\x25\x0A\xD0\x0A\x96\x2A\x86\x2E\x84\x32\x0A\xEB\x0A\x92\x3A\x86\x3A\x84\x57\x10\x09\x8E\x8E\x8A\x80\x03\x99\x86\x35\xB7\x8C\x99\x9A\x9C\x9F\x9A\x9F\x33\xC0\xB4\x8A\x8A\x9F\x7E\xA0\x9C\x44\xBD\x89\xBF\x95\x9A\x85\x00\xA7\x50\x89\x82\x11\xA6\x83\x00\xAB\x81\x04\x57\x82\x85\x0A\xA9\x82\x03\xAE\x00\x07\x20\xA8\x00\xB5\xA3\xA3\x9D\x0A\x89\x25\xAA\xA2\x9C\xB6\x82\xB3\x4B\xC1\xB1\xA3\xAD\xB4\xA5\xBA\xB9\x77\xF4\xAF\xAE\xB3\x80\xB9\xBC\xA4\x7F\xE8\x81\xC6\xA3\xB8\xC3\xBC\xBB\x87\xF8\x89\xDA\xBD\xBC\xBF\x84\xC7\x01\xFE\x8B\xC6\xCD\xC0\xC5\xCA\xC5\x97\x8C\xCF\xD6\xCB\xC8\xCD\xCE\xCD\x91\x90\xF6\x82\xD2\xC9\xCC\xCB\xCF\xA7\xA1\xDC\xCA\xDE\xCC\xD4\xD1\xD1\xAB\xB0\xED\xD2\xDF\xD5\xD0\xD4\xC1\x93\xB8\xE6\xDA\xD7\xDC\xC3\xC1\xB3\xBE\xB9\xC1\xFB\xD3\xE2\x82\x04\xB0\x0B\x0A\x96\xBF\xD5\xC4\xDE\xD7\xD4\xB4\xD0\xF6\xCF\xEE\xE1\xE9\xEB\xE9\xD6\xC5\xD4\xFA",
			"\xE9\xE8\xE2\xEF\xE6\xDC\xD8\xE2\xE4\xD4\xF1\xDB\xF0\xF3\xE5\xB3\xE7\xEA\xF9\xF5\xD9\xF6\xE9\xEF\xD7\xF1\xFC\xEE\x00\xB3\x06\xE5\xE0\xDF\xCC\xFB\xF2\xE2\xFD\xFF\xFC\x00\xBC\x74\x72\x7F\x03\x81\x8F\x7E\x80\xBD\x44\x89\x82\x81\x05\x88\x8B\x76\x82\x0F\x8C\x8B\x82\x83\xDD\x52\x81\x84\x85\xD8\x48\x46\x43\x53\x09\x53\x08\x7C\x86\xF3\x50\x85\x84\x88\xE8\x65\x8C\x7A\x89\xEE\x68\x80\x7E\x8A\xF2\x6C\x81\x79\x88\x16\xA3\x87\x83\x8C\x0D\xB4\x83\x86\x8D\x17\xB8\x82\x8D\x8D\x3C\xB7\x83\x42\x05\x60\x57\x0F\x86\x8E\xEB\x69\x87\x8B\x91\x46\x89\x9B\x88\x92\x4B\x8A\x9D\x88\x93\x4F\x8E\x9F\x8A\x8B\x22\x85\x9D\x93\x95\x51\x98\x93\x94\x94\x5B\x92\x95\x94\x8C\x14\x9A\x00\x5B\x06\x43\xBD\x89\x8E\x99\x3B\xBE\x8A\x9B\x99\x6B\xA9\x9C\x9B\x9B\x6E\xB1\x96\x95\x96\x74\x9D\x9A\x97\x97\x54\xB1\x83\x9E\x9D\x75\xB8\x9C\x96\x9F\x5E\x8A\x4E\x04\x58\x1F\x25\x9D\x9B\x9E\x80\xB7\x9A\x9C\x98\x44\x8C\xA8\x98\xA2\x8B\xB9\x94\x8B\x9F\x91\x94\xA3\xA5\xA0\x97\x8A\xA9\xA5\x9F\x0A\x62\x00\x5B\x08\x86\xB0\x90\xA7\xA6\x7C\xA5\xA9\xA0\xA7\xA4\xA7\xA6\xA9\xA5",
			"\x98\x8D\xA2\xA6\xAB\x96\xB0\xAD\xAB\xA3\x8E\x87\xA5\xAD\x40\x26\x20\x57\x09\xA8\x72\xB7\xAD\xAF\xAB\xB4\x80\xB6\xAE\xB0\xA2\xBE\xA3\xAA\xAC\x9A\x88\xB8\xAA\xB2\xAB\xA9\xAC\xA9\xB2\xC1\xB3\x6A\x08\x58\x2B\x3C\xA7\xB1\xB4\xB3\x83\xB1\xAC\xB6\xD0\x9A\xB9\xB5\xB1\xC4\xBF\xAB\xB6\xB7\xDD\xA0\xB3\xBA\xB9\xDF\xA2\xB9\xBB\xB5\xE4\x8B\xBC\xB6\xBB\xED\x8D\xBC\xB2\xAA\xF4\x8F\xB0\xBC\xBA\xE5\x80\x0E\x0B\x5A\xE1\xAC\xB8\xBF\xBD\xEA\xB9\xBE\xBC\x00\x2F\x20\x58\x45\x42\xCB\x73\xB6\xBE\xBC\xEF\x8C\xC1\xBD\xBD\xCE\x91\xCA\xC2\xC4\x0D\xD0\xC3\xC7\xC5\x15\xCB\xC6\xC5\xC6\x14\xCF\xCA\xC7\xC7\x1D\xFF\xBE\xC2\xC8\x1B\xDE\xC1\xC9\xC0\xD5\x73\x0C\xBF\xB9\x28\xE3\xCD\xC9\xC9\x24\xE0\xC8\xC6\xC9\x33\xF1\xC7\xCB\xC0\x38\xC6\xBA\xCD\xBF\x3B\xEC\xC9\xCD\x6C\x34\x2B\xC9\xB9\x0D\x60\x76\x06\xB5\xCF\xEB\x88\xD2\xC2\xD2\x00\xFF\xCE\xCC\xD3\x2E\xCE\xD9\xD0\xCF\x54\xCF\xD5\xD7\x6B\x39\x20\x5A\x0F\xD1\x57\xCB\xDD\xD5\xD3\x50\xF0\xCF\xCA\xCC\x1C\xF5\xC3\xDB\xCD\x61\xE4\xD4\xCD\xD9\x6C\xEB\xDE\xDA\xCD\x66\xD2\xDE\xD6\xD5\x74\xD3\xD5\xDF\xDC\xAF",
			"\x7D\x02\xD0\xDE\x7C\xE0\xDF\xD5\xD4\x69\xE8\xDF\xDE\x88\x1C\x49\x4C\x86\x41\x3F\x20\x50\x10\x58\x41\x20\x52\x10\x58\x43\x20\x5E\x46\xE1\x0A\x45\x10\x5A\x11\x7B\xC0\xC7\x11\xE6\x80\xC3\xEA\xD8\xDC\x6D\xF0\x98\x10\x58\x49\x1C\xD7\xDE\xDF\xA7\xDD\xE9\xEA\xD8\x72\xE8\xE6\xDF\xEB\x7D\xEA\xE0\xEE\xEB\xB1\xEC\xE1\xE1\xDC\xB7\xE1\xE7\xD8\xEE\x9E\xC2\xEB\xEB\xE7\x71\x8C\x1C\xE6\xED\xBD\xFC\xEF\xEE\xEF\xB3\xF2\xE5\xEC\xF0\xAD\xCA\xF4\xEF\xF3\xCE\xD1\xF4\xF3\xF1\x3A\x8D\x13\xF0\xF3\xB9\xEF\xDB\xEE\xEE\xCD\xD3\xF9\xF2\xF7\xCB\xD4\x8E\x13\xF5\xC8\xE1\xF6\xF3\xF7\xD8\xC5\xFC\xF5\xF6\xA0\xDA\xFD\xF5\xFA\xD4\xE8\x9F\x10\xF9\xE7\xE6\xFB\xF9\x6C\x22\x54\xE9\x41\x14\xA6\xE8\xF5\xF8\xF4\xE0\x60\x80\xFC\x7E\x75\x7E\x01\x89\x24\x0A\xF4\x77\x7D\xFC\x6E\x7C\x7D\xED\x4C\x82\x7D\x0F\x8B\x81\xFB\x13\x8E\x80\x0A\xAF\x79\x21\x55\x09\x81\x04\x84\x8A\x80\x0E\x9B\x86\x7E\x1F\x86\x81\x01\xD2\x73\x80\x10\x96\x85\x81\x17\x83\x85\x00\xA4\x8F\x7E\x16\xAA\x85\x84\x22\x9D\x82\x09\x80\x04\x24\xFD\x6F\x85\x85\x2B\x99\x84\x0C\xAE\x82\x87\x18\xA1\x84",
			"\x87\x3F\x9A\x84\x0E\xBB\x85\x27\x2B\x20\x28\x0B\x1A\x87\x84\x04\xCA\x82\x83\x0A\x8E\x89\x85\x3D\x80\x88\x13\x9E\x83\x8B\x19\x99\x09\x89\x4F\x88\x86\xAF\x5A\x08\x8A\x28\x81\x8C\x88\x60\x83\x8A\x18\xB7\x84\x8D\x28\x82\x8D\x8C\x5F\x83\x8E\x19\xE1\x88\x8D\x2A\xBE\x86\x8D\x52\x99\x89\x6C\x5B\x0D\x8A\x2D\x8B\x8A\x8E\x4D\x9E\x88\x1C\xE7\x8B\x8D\x93\x5C\x0D\x8E\x77\x9A\x8C\x1E\xD4\x83\x91\x19\x82\x97\x90\x76\x99\x8D\x22\x84\x98\x3B\x2E\x00\x92\x91\x81\x8B\x92\x21\x92\x9F\x8D\x42\x95\x90\x91\x91\x99\x90\x24\x9B\x9C\x90\x4A\xAE\x66\x24\x36\x9D\x8D\x1B\x96\x91\x8E\x4C\x9C\x93\x92\x9A\x9D\x91\x2A\xA8\x97\x95\x4B\x9E\x94\x8F\x69\x83\x96\x29\xAA\x9D\x95\x52\xBE\x57\x0B\x8F\x94\x95\xBA\x60\x09\x96\x56\xBA\x96\x97\xC0\x8E\x97\x2A\xC2\x95\x96\x58\xBB\x8C\x8D\xA2\x89\x99\x2C\xCA\x97\x98\x35\x8B\x9F\x99\xCD\x92\x97\x2B\xC8\x90\x9A\x52\x86\x9E\x9A\xD4\x90\x4D\x18\x3D\x94\x99\x5F\x9D\x99\x98\xB6\x83\x99\x38\xC5\x99\x9A\x6C\xA7\x62\x0C\x58\x83\x0C\x37\xE3\x9E\x9A\x76\xA0\x9F\x9A\xB3\x8F\x9D\x39\xF1\x90\x60\x94\x21\x95\x4D\x65\x0B",
			"\x9C\x3C\xD3\x94\x42\x33\x3A\x9B\x9E\xFC\x92\x9A\x38\xFB\x93\xA0\x80\x85\xA6\x99\xD1\x8C\x9A\x39\x82\xA4\x9C\x84\x8B\xA2\x77\x67\x1F\x9E\x43\xF4\x9E\x9D\x6F\x96\xA5\xA2\x18\xA4\xA1\x43\xE6\x68\x0C\x89\x8C\xA5\x9D\x1A\xA0\xA6\x41\x9B\xAA\xA0\x8A\xA1\xA2\x9E\x13\xA1\xA2\x42\xE9\x0E\xA3\x92\xAA\xA5\x9A\x26\xA3\xA6\x48\xA9\xA7\xA1\x8F\xA8\xA6\xA6\x17\xA7\xA5\x4E\xB2\xA7\xA6\x97\xB5\xA3\x20\x6A\x0D\xA4\x4C\xBE\x5A\x25\x7B\x89\xA3\xA8\x3F\xA8\xA8\x49\xCA\xA3\xA6\x9C\x99\xA4\xA7\x3B\xB4\xA7\x52\xC7\xA4\xAB\x87\x8C\xAD\xA7\x57\xB1\xAA\x53\xBA\xAF\xA8\xA9\x8D\xA8\x4D\x6C\x02\xA9\x55\xB1\xAE\xAA\xAC\xA3\xAF\xA5\x67\xA9\xA9\x5A\xB3\x3D\x0C\x2C\xAE\x0A\xAC\x56\xAB\xAF\x57\xD9\xAD\xAB\xAD\x90\xAD\xAE\xBA\x6F\x0C\x16\xF0\x00\xAE\xB2\xB6\xA9\x21\x71\x1D\xAC\x5A\xF1\xA4\xB0\xBF\xBE\xA3\xAA\x85\xA3\xB2\x61\xF4\xAC\xAB\xC6\xB7\xAE\xB1\x0E\xAC\x26\x51\x89\xBA\xAC\xCA\x8D\x8B\x0E\x82\xB5\xB3\x62\xF2\xA6\xAC\xCB\xB3\xAC\xB3\x5A\xA7\xB3\x67\x9E\xBD\xB3\xCD\xA4\xB1\xB4\x8C\xAF\xB2\x6A\xE5\xA8\xB4\xD0\xB8\xA9\xB5\x0E\xB4\x0D\x66\x88",
			"\xB6\xB5\xDA\x8A\xB7\xB6\xB1\x35\x0C\x58\x2E\x23\xB3\x3B\x20\x28\x0F\x60\x39\x0C\x58\x7A\x00\x2D\x3D\x20\x2C\x0F\x60\x3D\x0C\x5C\xFE\x03\xB7\xD1\xB6\xB1\x5C\x7F\x0D\xB9\x69\xB8\xB4\xB6\xEA\x8E\xBE\xBA\xD3\xBA\xB0\x76\xAD\xB7\xB5\xD7\xAE\xB0\xB2\x7F\xA3\x94\x20\x52\xBC\xBB\xE7\x95\xBA\xBB\xE8\xA7\xBE\x7A\x84\x91\x10\xF2\x9E\xBD\xBB\xE0\xA2\xB5\x76\xEB\xB9\x5E\x41\x2E\xB9\xBE\xB0\xA1\xBE\x7C\xE5\xBB\xBB\xF7\xA6\xBF\xBA\xE9\xA0\xC1\x13\x83\x17\xBF\xD5\xBA\xB9\xBF\xFB\xB1\x8C\x21\x05\xCC\xB4\xFF\xBE\x55\x10\x0C\xC7\xC3\x77\x86\xC9\xC0\xB1\x46\x11\xC2\x15\xC5\x9F\x21\x18\xC8\xC1\x0E\xD3\xC5\xC1\xF8\xBF\xC2\x84\xF0\xB4\xC2\x0F\xE4\xC0\xC4\x25\xD4\x80\x22\x1C\xC2\xC5\x0C\xE8\xC4\x42\x89\x00\x2E\x22\x2C\xC7\xC5\x11\xFF\xBB\xBE\x02\xD9\xC4\x8E\xBB\xCC\xBF\x00\xFC\xC6\xC1\x3E\xDD\xC4\x62\x8B\x14\xC7\x1B\xC2\xCA\xC7\x47\xDF\xC5\x88\xB5\xCE\xC4\x1B\xFD\xBB\xC9\x46\xD1\x8C\x23\x45\xCF\xC9\x14\xC0\x05\x11\x54\xC1\xC8\x90\xF4\xB9\xC9\x2E\xDB\xC8\xC9\x5F\xCA\xCA\x95\xD1\xC0\xCB\x06\x8E\x11\xCB\x5C\xC1\xCE\x97\xCB\xCF\x10\x34",
			"\xE0\xCD\xCC\x5A\xD0\xCD\x9A\xF2\xCF\xCD\x31\xD5\xCF\xC5\x4E\xD1\xCE\x9D\xFA\xC8\xCE\xDD\x50\x10\x2C\x91\x00\x2E\x24\x60\x23\x12\xB0\x14\x10\x2C\x95\x00\x2E\x25\x60\x27\x12\xB0\x18\x10\xAE\x99\x0E\xCE\x98\xFD\xC2\x20\x4D\x12\xD3\xCD\x7B\xD3\xCD\xA6\xF5\xC4\xD3\x16\xE6\xC4\xCC\x9B\xD3\xD1\x9E\x9A\xDE\xA1\x4D\x17\xD2\xCD\xA8\xD4\xCE\xA8\xCD\xCC\xD4\x13\xDC\x17\xD4\xAA\xD8\xD0\x85\x1D\x10\xD7\x50\xF2\xD3\xD4\x9C\xD8\xD7\xAA\x9F\xD7\xCE\x5D\xF7\xD5\xD5\x9E\xC1\xD8\x93\xBC\xD1\x5C\x4F\x20\x2F\x13\x60\x20\x14\x58\x21\x10\x2C\x51\x20\x2B\x14\x60\x24\x14\x58\x25\x10\x2C\x53\x30\xAF\x14\xB5\xDD\xD3\xB0\x81\x28\x15\x6C\xFE\xD1\xD5\xB6\xC0\xDE\xB6\xA0\xD3\xDD\x5E\xC0\xDB\xDB\xE8\xC4\xDF\xB7\xE2\x69\x14\x6F\xE7\xDA\xDD\xEF\xC6\xDC\xB1\xA4\xD6\x6C\x55\x2E\xDB\xDE\xA3\xAB\x17\xBD\xC2\xD0\xDE\x7C\xFB\xD4\xDF\xF2\xC0\xE0\x9F\xEB\xD1\xDD\x58\xE2\xDC\xE0\xE5\xC3\xE1\xBC\x8A\xEA\x7A\x56\x3B\xD9\xDD\x01\xF0\xE3\x1D\xAD\x10\x2C\x57\x0F\xE5\xDF\x02\xF3\x37\x2B\x17\xE1\xE2\x8C\xD2\xE3\x36\xB0\x1C\xE0\xC3\x99\xEF\x35\x58\x22\xE4\xDE",
			"\x0B\xE8\xE6\xBF\xBF\xDB\xE5\x38\xB2\x17\xE4\xB9\xC8\x4F\x2C\x30\xEF\xDF\x8F\xF1\xE5\xE5\x06\xF9\xE5\xC1\xBB\xE9\xE0\x95\xE4\xE0\x3A\xB4\x14\xE4\xCB\xBF\xE3\xE9\x38\x75\x12\xE8\x07\xE9\xE7\xCD\xC4\xE9\xE8\x9C\xFC\xE0\xE1\x50\xEA\xE9\xCD\x9E\xE4\xEB\x8E\xE2\x36\x16\x60\x37\x14\x58\x38\x10\x2D\x5C\x20\x2A\x17\x60\x3B\x14\x58\x3C\x10\x2D\x5E\x20\x2E\x17\x70\xBF\x14\xD2\xBA\xE7\x64\x60\x2B\xEF\xE9\x52\xE5\xE9\xD5\xA3\xE6\xE7\xA9\xD6\xEC\xEE\x73\xFE\xE5\xDD\x80\x61\x19\xB7\xFD\xE3\xE9\x7B\xED\xE8\xD3\xEC\xE6\x20\x61\x3E\xE9\xEA\x4E\xE9\x23\x30\x07\xF1\xEE\xC1\xC1\xF4\xF0\x8D\xF0\xF1\xE2\x88\xF3\xF0\xB8\xD3\xF1\xF2\x96\xF5\xF3\xDF\xB3\x84\x18\xC6\xD7\xF7\xF3\x9A\xE6\x21\x31\x1E\xF1\xF4\xCC\xC9\x26\x18\xA4\xEF\xF1\xE6\xAA\xFB\xF2\xB9\xD1\xE7\x18\xA9\xFE\xE0\x32\x31\xF7\xEE\xBD\xF9\xE8\xF0\xB7\xF6\xEC\xDE\xB5\xF8\xF6\xDE\xF9\x59\x19\xB4\xFB\xF5\x65\xCA\x10\x2D\x65\x20\x2C\x19\x60\x2D\x18\x58\x4E\x10\xAF\x67\x01\xFE\xF6\xBE\xEE\xF6\xF0\xD0\xF3\xFB\xDE\xD5\xFA\xF7\xD4\xE8\xB0\x34\x4F\xF6\xFB\xEC\xDD\xFF\xFB\xD8\xE3\xB5",
			"\x34\x5C\xF1\xFD\xF2\xD2\xFE\xFB\xE6\xEF\xBE\x34\x64\xF7\xFC\xF0\xED\xF9\xFD\x92\xF5\xAB\x34\x6C\xFE\xF1\xDC\xEF\xFF\xFE\xF5\xE3\xB0\x35\x74\xF1\xFE\xD6\xD4\xF6\xFF\xA6\x7F\x7F\xD8\x15\x0D\x60\x16\x0D\x60\x17\x0D\x60\x18\x0D\x60\x19\x0D\x70\x5A\x0D\xFC\x7B\x7A\x82\x4B\x0D\x0F\x8D\x7A\xF9\x77\x7D\xF8\x7D\x7F\xF6\x75\x81\xE8\x75\x1D\xDC\x00\x16\xDD\x00\x16\xDE\x00\x16\xDF\x00\x16\xE0\x00\x57\xE1\x03\x81\x02\x8D\x40\xE2\x08\x82\x0A\x53\x0E\x2C\x80\x7A\x00\x80\x83\x19\x88\x81\x11\x74\x0E\x60\x15\x0E\x60\x16\x0E\x60\x17\x0E\x60\x18\x0E\x70\x59\x0E\x2F\x85\x7A\xD5\x4A\x0E\x41\x81\x83\x42\x87\x84\x46\x89\x84\x33\x80\x81\xBE\x2B\x0E\x70\x5C\x0E\x60\x1D\x0E\x60\x1E\x0E\x60\x1F\x0E\x60\x10\x0F\x70\x51\x0F\x45\x8B\x84\x27\x32\x0F\x5B\x8D\x40\xF3\x00\x57\xF4\x00\x16\xF5\x00\x16\xF6\x00\x16\xF7\x00\x16\xF8\x00\x57\xF9\x0F\x85\x16\x81\x47\xFA\x0E\x86\x4D\x41\x0B\x53\x16\x10\x75\x82\x1C\x03\x37\x87\xC4\x19\x87\xE0\x1C\x87\x83\x1E\x87\x78\x8E\x2B\x7A\x8D\x1B\x80\x8B\x87\x82\x8D\x87\x87\x8F\x87\x89\x81\x88\xE1\x27\x38\x03\x14",
			"\x16\x93\x59\x15\x09\x1D\x00\xE0\x1C\x15\x09\x1A\x21\x03\x1E\x88\x02\x12\x16\x8A\x87\x13\x9A\x81\x10\x90\x8B\x21\x0A\x12\x89\x06\x14\x89\x83\x16\x89\x06\x18\x89\x02\x1F\x89\x61\x18\x88\x37\x13\x88\xDB\x15\x14\x09\x38\x26\xAC\x81\x8A\x99\x83\x8A\x0A\x16\x8A\xC2\x18\x8A\x03\x1A\x8A\x01\x1C\x8A\x9C\x8C\x88\x33\x10\x8B\xD9\x12\x8B\x31\x25\x8B\x60\x14\x8A\x03\x1A\x8B\xC4\x1C\x8B\x07\x10\x16\xC1\x86\x88\xAF\x8E\x8A\x33\x13\x8B\x6D\x2C\x8A\x35\x1C\x8A\xCA\x82\x10\xCC\x8D\x1B\xCE\x81\x10\xBE\x80\x00\xC0\x84\x8D\x0E\x18\x8D\xC9\x89\x8B\x95\x8A\x10\xE1\x83\x8E\x9D\x83\x8C\xE4\x8D\x10\xD6\x80\x27\xE6\x81\x89\xE8\x87\x8A\xEA\x80\x8D\xEF\x8C\x10\xC4\x85\x14\xC6\x84\x21\xF3\x82\x8A\x09\x1B\x8D\x01\x1D\x8D\xDB\x1F\x8D\x04\x18\x8F\xED\x8E\x10\xFB\x8C\x8F\x37\x11\x8F\x71\x2C\x8A\x06\x9A\x8D\xF5\x8B\x8B\xF7\x83\x59\xD1\x84\x88\x3A\x10\x91\xE7\x83\x89\xE9\x87\x89\x08\x92\x8C\x0A\x99\x8F\xFF\x0E\x90\xD8\x1A\x91\xF4\x8C\x91\xF6\x8E\x91\x16\x92\x92\x0B\x9C\x90\x0E\x14\x92\xA2\x16\x92\x00\x96\x10\x02\x90\x00\x04\x99\x1D\x06\x9B\x8E",
			"\x0A\x17\x91\xB1\x8A\x13\x2D\x9E\x92\x0C\x10\x93\xB1\x1C\x8E\x33\x98\x15\x13\x9D\x8C\x15\x95\x94\x9B\x82\x92\x44\x97\x8B\x01\x97\x94\xDE\x89\x94\x4E\x96\x10\x3C\x95\x8C\x3E\x92\x92\x42\x93\x1B\x4D\x9B\x8A\xB8\x88\x92\x14\x9A\x92\x4A\x91\x10\x55\x90\x94\x21\x99\x90\xF0\x87\x8C\x3B\x9B\x91\xA5\x8D\x91\xA9\x8F\x91\xD2\x8E\x8E\x66\x91\x94\x68\x98\x30\x6A\x9B\x8C\x6C\x9D\x8B\x6E\x98\x91\x9E\x8C\x2B\x12\x9E\x95\x48\x90\x96\x53\x93\x10\x63\x94\x96\xFA\x88\x95\x73\x95\x15\x75\x9C\x8D\x77\x9F\x8C\x2B\x91\x97\xFF\x0F\x93\x40\x99\x95\xAF\x1C\x8A\x0E\x9D\x97\x6B\x99\x92\x6D\x9D\x98\x20\x9D\x10\x90\x9E\x92\x92\x90\x1D\xAC\x84\x8C\x96\x96\x97\x98\x98\x97\x9A\x9F\x96\xE5\x8A\x10\xA2\x9D\x95\x97\x9F\x95\x99\x91\x96\xAD\x8E\x98\x9D\x9C\x90\x9F\x95\x1D\xA1\x99\x98\x03\x9B\x98\xE0\x89\x97\x3D\x93\x8D\x8E\x95\x9B\xDC\x17\x9B\x27\x9D\x9A\x7F\x9F\x9A\x81\x9B\x94\xB2\x96\x98\xFE\x80\x16\xA3\x9A\x98\xA5\x9C\x98\xB0\x93\x98\x84\x9C\x8A\xD4\x9C\x9A\xA4\x9E\x9A\xA6\x91\x9D\x2C\x9A\x9C\x3A\x25\x9D\xC3\x97\x9D\xC5\x99\x9D\xC7\x92\x96\xDB",
			"\x9F\x9B\x87\x93\x9E\xE2\x86\x9D\xCE\x98\x9D\xD0\x98\x9E\xD2\x94\x96\xB3\x9C\x8F\xC0\x99\x8D\x0A\x1F\x15\xDF\x9B\x9E\xE1\x9D\x9E\x5C\x99\x10\xEF\x90\x94\xAC\x86\x9F\xB0\x95\x93\x37\x95\x14\x39\x9C\x9B\x56\x9E\x9B\x9B\x92\x97\xCB\x99\x10\x00\xA8\x9E\x02\xAA\x9B\x07\x97\x9A\x7A\x90\x97\x09\xA3\x92\xE7\x92\x10\x0D\xAB\x9F\x34\x90\x95\x05\x92\x95\x1A\xA2\x98\xE5\x95\xA1\xF3\x98\x9B\xE9\x9F\x94\x7E\x91\x95\x80\x9F\xA1\xC8\x95\xA1\xCD\x9F\x8B\xEA\x99\x9B\xCF\x9B\x9B\x12\xAD\x9B\x14\xA8\x9A\x67\x9B\xA0\x1B\xA7\x9F\x30\xAC\x9E\x32\xAA\x9D\xC9\x96\x9E\x38\xA6\x94\x3A\xA6\x93\x10\xAA\x93\xFC\x91\xA2\x36\xAA\xA0\x3A\x20\x1C\x0E\x95\x93\xC0\x16\x90\x4D\x1A\x10\x11\x9C\x2B\xFD\x9E\x92\x4E\xA0\xA1\x51\xA9\x10\x53\xA4\x97\x47\xAF\xA3\x22\xA1\x23\x57\xA1\xA3\x59\xAA\xA5\x60\x1E\x90\x55\xAC\x90\xF1\x9D\x8F\x3A\x21\xA6\x3C\xA3\xA6\x06\x1B\xA5\x88\x9D\xA5\x15\xA9\xA6\x3A\x13\xA2\x6E\xA9\x1D\x6C\xA4\x1C\xC4\x85\x93\x0C\x00\xA1\x11\x07\xA7\xB1\x95\xA1\x7C\xAE\xA7\x80\xA7\xA6\xFC\x84\xA7\x0D\x90\xA6\x0A\x1D\xA7\x62\xAF\xA7\x77\xA6",
			"\xA8\x45\x18\xA8\xD5\x8A\xA8\x09\x1C\xA8\x6D\xAE\xA8\x6E\xA0\xA9\x57\x90\xA4\x6B\xAC\x39\x06\x94\x8C\x35\x1A\xA9\x37\x15\x93\xAC\x84\xA0\xAA\x95\xA8\x48\xA3\xA1\x2F\x94\xA9\xB0\x96\xAA\x52\x18\xAA\x5E\xA9\xA4\x16\xA4\x21\xA4\xA0\xA1\xA0\xA9\x96\xB1\xAA\xAA\x37\xAB\xA4\xE0\x14\x8C\x92\xA9\x2E\xBF\xA9\x2F\xC1\xA0\x30\xC3\xAE\x32\xC5\xA2\x22\xC7\xA1\x23\xC9\xA4\x21\xCB\xAA\x23\xCD\xA8\x26\xCF\xAD\x26\x35\x96\x8B\x28\xA6\x10\xC9\x17\xA7\x06\x96\xA9\x03\x14\x8C\xA2\xA3\x13\xD3\xA0\xA1\xD7\xAE\xA6\xD9\xA7\xAA\x72\xA2\xAB\xC5\xA6\xA7\x39\xA6\x10\xD4\xAD\xA1\x09\x11\xAE\x63\xA3\xAE\xAF\xA5\xAE\xBA\xA5\x98\x9C\xA8\x26\xDF\xA2\xA6\xEE\xA9\xA5\xF0\xA6\x87\xB8\xA3\xA7\xDC\x98\x26\x4C\xA0\xA8\x45\x1F\x8F\xC4\x14\xB0\xBD\x1D\xA2\x00\x05\x1F\x62\xAE\x21\x8F\xA2\x92\x35\x9A\xB0\x6D\xAC\xB0\x99\xA9\xAA\x34\xAB\xAA\xB4\xAA\x10\x10\xB9\x9F\x01\x12\xB1\x63\xAD\xAD\x65\x9F\xA5\x17\xB9\x10\x19\xB5\xAD\x03\x1C\xB1\x59\xAE\xB1\x9C\x9F\xAF\x6D\x20\x1C\xC2\x95\xA1\x22\x2C\xB2\x02\xBA\x13\x50\xAD\xAB\x31\xB7\x13\x06\x95\x93\xF1\x97\xB3",
			"\x60\x16\x90\x0E\x96\xA6\x22\x90\x1C\x79\xAD\x1B\x0E\x91\xAD\x70\x25\x93\x06\x9E\xAA\xEA\xA0\xAB\x2E\xB0\x1E\x2D\xB2\xAB\x2F\xBC\xB4\xE4\xAB\xB4\x14\x20\xB4\x51\xBE\xB4\x31\x24\xB5\x26\xA9\xAE\x1A\xB0\x00\x19\xAE\xA2\x64\xA2\xAF\x01\x1E\xB3\x8E\x90\x1C\xBE\xAF\xB3\xAC\xA3\x10\x14\x00\xA1\x62\x2D\xB0\x63\xB0\xB5\xF1\xA2\xB5\xBC\xA3\x18\x4D\xB3\xAF\x2E\x38\xB5\xFC\xAD\xB6\x53\xB0\x1E\x35\x95\x93\x26\xBC\xAE\x06\x1D\xB5\x25\xAF\xA6\x0A\x10\x11\x5C\xA4\x95\x66\xB3\x18\x65\xB8\xB7\x71\xB2\x1C\x73\xB5\xB1\xC2\xA7\xB8\xCE\xA0\xB9\xD0\xA2\xB9\x6D\x24\xB4\x71\x26\xB9\xD8\x18\xB9\xA2\x1A\xB9\xB1\x1C\xB9\xB3\x1E\xB9\xAF\x15\x93\x98\xAB\xB5\x42\x23\x59\x06\x98\x01\x54\xA4\xB9\xDB\x11\xB4\xDB\x19\xB8\x70\xB3\xB9\x8A\xB0\xB0\xE0\x13\xB4\xAA\xB1\x27\x01\xB9\xB5\x03\x11\x13\x62\xA0\xB8\x35\x16\x90\x15\x05\xB5\x2B\xA6\xB5\x72\xB0\xBC\x8E\xB4\xAC\xB5\xB5\x92\x60\x14\x8C\x06\x90\x24\x6F\xB0\xA2\xB9\xA5\xBC\x2E\x36\xB0\x01\x1A\xBC\x0A\x1C\xBC\x77\xB6\xB8\xCF\xB7\xA0\x2C\x30\xBA\xD0\x1C\xBD\xD5\x1E\xBD\xDC\x10\xBE\x35\x12\xBE\xC4",
			"\xBA\xBD\xC0\xA7\xBC\x9B\xB8\xBE\x9D\xBA\xBE\x9F\xBC\xBE\xAF\x14\xBE\xB8\xB6\x1C\x10\xA7\x1F\xCD\xB1\xBC\x74\xB7\xBB\x6E\xA3\xB0\xE5\xB4\x98\xC6\xB1\xBB\x95\xBE\xBE\xDD\xB0\xC0\xDF\xB2\xC0\xE1\xB4\xC0\xE3\xB6\xC0\xFB\xBC\xBF\xC8\xA8\xC0\xF5\xB0\xBD\x0B\xCE\xBF\x45\xBA\x10\xF9\xAE\xB7\xB9\xB5\xBE\x28\xB5\x27\x0E\x90\xB3\x0D\xC6\xBE\xF9\x2A\xC1\xD7\xB2\xBC\x91\xB0\xC1\xB6\xB6\xAB\x0C\xC9\xBF\x32\xB5\xB3\x33\x1A\xB3\x09\x1A\x16\xBB\xBB\xB3\x1C\xA0\x00\x0E\x96\x90\x23\xB1\x10\x35\x97\xC1\xA5\x2E\xBA\x20\xC0\xBB\xAF\xBF\xBF\x22\xC9\xB9\x25\xCB\xAD\x3F\xC2\x10\xF0\xBF\xC1\xF7\xBA\xAC\x41\xC3\xBD\x47\xC0\x00\x43\xC0\xC4\x3D\xC2\x1A\x35\xC0\xA1\xC7\x1B\xC1\x36\xC8\xBF\x63\xAA\xBF\x1B\xCC\xBF\x75\xBE\xB6\x44\xCE\xC0\x57\xBA\xB7\x28\xCE\x10\x7B\xB5\x9F\x10\xA0\xB8\x32\x93\x10\x2C\xC1\xA7\xD8\xBB\xC3\xAD\xB9\xC0\x84\x9F\xC0\x6A\xC7\xB9\x49\xCB\xC4\x42\xC1\xC7\x49\xC6\xC3\x76\xC2\x92\x77\xC9\xBD\x58\xCE\xC6\x39\xCC\xC3\x6F\xCE\xC3\x4D\xCB\xBE\x81\xCD\xBE\x83\xCF\xBE\x74\xC5\xC8\x01\xC8\xC8\x03\xCA\xC8\x05\xCC\xC8\x07\xCE",
			"\xC8\x6C\xC4\x96\x7C\xC5\xC4\x14\x26\x90\x33\xB0\xB6\x1C\xC4\xAF\x7F\xC9\xBE\x90\xC7\xC5\x0A\xC6\xC4\x9D\xCB\xC5\x99\xC6\xAC\x87\xCB\xC9\xB1\x15\x93\xF4\xBD\xA6\x69\xB8\xAD\x0A\x1B\xCA\x3E\xAE\xAF\xA1\xCC\xC4\xA6\xC4\xC8\xB3\xC6\xC8\xB1\xC3\xC7\xB7\xC8\xC4\xB9\xCA\xC4\x49\xC8\xCA\x10\xAE\xCA\xEF\xAD\xCA\x06\xA8\xC5\x72\xCA\xCB\xB5\xC9\xC8\xC7\xCB\xC8\xC9\xCD\xC8\xCB\xCF\xC8\xCD\xC1\xC9\x40\x92\x22\xC0\x94\x8C\xC0\x9D\xB3\xB3\xBD\x3F\xBB\xA3\x10\xD5\xC8\xCD\x4A\xAA\xCD\x34\xB5\xB8\x7A\xAC\xCD\x8F\x92\xCE\xD4\xC7\xCD\xE0\xCD\x1B\x35\x90\x9C\xE9\xCF\xCD\x68\xC4\x1C\xB4\xBA\xC7\xFC\xB5\xAC\xF2\xC4\xB1\xA3\xC7\xAE\x31\x28\xAE\xB2\xC2\xAB\xF8\xC2\x10\xC0\x94\x99\x5A\xC3\x10\x96\x60\xA8\x02\xD3\xD0\x04\xD5\xD0\x81\xB9\xCF\xFC\xCF\xA2\x00\x06\xC9\x52\xAD\xD0\x5F\xB2\xB8\x0F\xD3\x10\x0C\xD1\xD1\x18\xAD\xAF\x8F\x89\x16\x0A\x11\xC5\x06\x1A\xD1\x03\x1C\xD1\xF2\xB9\x10\x1E\xD1\x10\x21\xD0\x00\x23\xD5\xD2\x19\xD2\xC1\x28\xDD\xAE\x29\xD6\xAD\x2B\xD3\x10\x13\xC0\x00\x2F\xD1\xD3\x8B\xAF\xC2\x33\xC0\x00\xA9\xC3\x10\x37\xD2\x10",
			"\x39\xD1\x10\x3B\xD6\xD3\x0A\x1D\xD3\x40\xDF\xD3\x42\xD9\x10\xBA\xB6\x10\xA3\xBA\x9F\x1B\xBA\x10\x7D\xB0\x00\xC0\xC2\x10\xBF\xB9\x10\xD6\xB3\x10\x47\xD1\x10\x51\xD8\xD4\x00\x05\xD5\x49\xD0\xD5\x4A\xD5\xBD\xC2\xCA\xD5\x09\x1F\xD4\x06\x15\xBA\x06\x18\xBA\x09\x13\xD5\x00\x04\xD6\xC6\x92\x10\x68\xD5\xB2\x0A\x1B\xD6\x02\x1B\xD4\x6E\xD1\x10\x4D\xD1\x10\x71\xD0\x00\x60\xD3\x10\x84\xB6\x10\x6B\xB6\x10\x58\xD0\x00\x66\xDB\xD7\x3F\x2E\xA1\x01\x10\xD8\x02\x1D\xD7\x4B\xD4\xD8\x54\xDB\xD5\x09\x18\xD8\x57\xDD\xD5\x7A\xDC\xD5\x5F\xDA\x10\x8C\xD2\xD6\x03\x14\x26\x5E\xD6\xD4\x0A\x16\xD9\x7C\xD2\xD8\x00\x0A\xD9\x81\xDD\x21\x99\xD0\xD9\x06\x1B\xD4\x9E\xD5\xD8\x8E\xD5\xD9\xA2\xD3\x10\x77\xD2\x10\xA5\xD1\x10\x94\xD2\x10\x1C\x09\xDA\x02\x16\xD6\xB1\xD7\xD9\xE2\x90\xDB\xB2\xD9\xD5\x06\x15\xDB\x9B\xD0\xDA\x09\x1C\xDB\x9F\xD6\x10\x73\xD0\x00\xC0\xD6\xDA\x91\xDF\xDB\x0A\x1F\xDA\x51\xAD\x01\x80\xA3\xDC\xD8\x15\x13\x95\x00\x8B\xFE\xC9\x10\x29\x0D\xC5\x09\x16\x09\xD2\xDC\x2B\xD5\xD9\xB7\x09\x17\x09\xD9\xD4\xD1\x01\x11\x34\xDC\xD6\x10\x98",
			"\x0F\xDD\x10\xD6\x10\xE2\xDB\xB8\x03\x19\x09\xE6\xD3\xA6\x3C\x06\xDD\x06\x1A\x09\xED\xD6\xBF\x01\x1D\x38\xE3\xD3\x10\x9B\x03\xDF\xE4\x99\x10\xF6\xDA\xDE\x02\x1C\x09\xFA\xD0\x00\xEB\xA0\x00\x98\x34\x21\xFB\xC0\x8A\x0A\x13\x3A\x06\xE0\xDF\x03\x13\x3E\xF7\xD2\x10\x9D\x01\xE0\x35\x18\x40\x0F\xE1\x10\x9E\x01\xE0\x23\xDC\x45\x15\xE0\x00\x9F\x01\xE0\x2F\xD4\x47\x1B\xE0\x0A\x1E\xEA\x10\x20\xEE\xDF\x01\x11\x0A\x12\xEA\x10\xE8\x4B\xE1\xA2\x01\xE0\x37\x9D\x51\x1B\xE3\x0A\x01\xE5\x93\x6D\x5B\xE0\x09\x14\x0A\x01\xE0\xB8\x81\x56\xE3\x06\x15\x0A\x01\xE7\xC6\x03\x1C\x57\x3C\xE3\x10\xA6\x01\xE0\xDA\xA2\x10\x7A\x53\xE4\x02\x17\x0A\x01\xE5\xD3\x6F\x5A\xE4\xDC\x61\xE0\x3D\xDA\x5B\x50\xE0\x00\xA9\x01\xE0\xC4\x82\x5B\x1B\xEA\x0A\xB0\x84\x8C\x53\xE7\xCF\xA0\xC6\x10\x5A\xE6\xE2\x00\x0C\x0A\x01\xE5\xD4\x03\x10\x5C\x1B\xED\x0A\x5D\xEA\x10\x68\xE2\x10\xC2\x5B\xE1\xAF\x07\xE6\x0A\x11\xE7\x64\xE0\x0B\x01\xEB\x0F\x80\xA7\xE0\x23\xCE\xC9\xB1\x15\x13\x03\xE5\x88\xB8\xC4\xE6\x86\xA2\x22\x38\xBC\xE0\x15\xD7\x32\x80\xB1\x9F\x02\xD3\xD2\x03\x33",
			"\xE0\x8C\xE0\xA8\x35\x93\x30\x23\xD1\xE9\x77\xA0\xE4\xDA\x37\xE4\xC6\xC2\xBB\xE0\xDE\x44\x35\xD6\xE9\x6E\xA0\xEA\x68\x2F\xE6\x9B\xEB\xB2\x6D\xD0\x3C\xE1\x82\xEA\x83\xE8\x9E\x03\x33\xDC\x93\xEC\xC9\x06\x1B\xDA\x14\x45\xD7\x80\xB0\xC8\xBD\xD6\x36\x83\x2C\xA0\x61\xE3\x10\xCA\xDE\x44\x24\x02\xC6\x55\xE5\xAA\xBE\x23\x2D\xF1\xB0\x27\x0E\x92\xEB\x4E\x4B\x2F\xBA\xE5\xE5\x7D\xD3\x30\xE9\xD3\x10\xB5\xE2\x1A\x0E\x9D\xEB\x03\x3B\x35\xCB\xED\xA9\x93\x53\x30\x8B\x35\xEC\x71\x25\x93\xC8\xE3\x30\x93\x3F\xB7\x67\xB6\xDC\x66\x30\x12\xD7\xE6\xAF\xC9\xD0\x3C\xF9\x32\xEE\x95\xC0\x57\x35\x4A\xB5\x6D\x2E\xBB\xC0\x3A\xE1\xEC\xEA\x23\xCB\xB0\x3C\xBC\x47\xEE\xF1\xE9\xEE\x27\x3E\x4F\xFA\xE0\x27\x64\xC0\x3C\x61\x5C\xED\xD8\x10\xB8\xDF\xEE\x2B\x42\xE5\xEF\x68\x20\xB8\xCD\xEE\x2B\xBC\x5A\xF0\x6D\x20\xB8\xD4\xEE\x2B\xC8\x5F\xEF\x71\x25\x95\xC2\xE1\x2E\xF6\x54\xF0\xA2\x15\x95\x07\xF1\x2E\x17\x66\xF1\xD8\x15\x95\x0D\xF1\x2E\x53\x62\xF2\x1D\xFC\xEF\x66\x33\x68\x28\xF1\x1B\x03\xE9\xF1\x2C\x3F\x68\x1C\xFE\xF2\x0A\x1F\xF1\x2C\x3F\x6A\x2D\xF3\x1B",
			"\x03\xE5\xF2\x2C\x3E\x6C\x39\xFF\x1A\x03\xE3\xF1\xE1\x2D\x6D\x3F\xF0\x1D\x98\xEE\xB5\x66\x36\x71\x33\xF3\x1B\x47\xF6\xD7\xC0\x3F\x72\x45\xF5\x1D\x4D\xFC\xF3\xE9\x2C\x75\x51\xFC\x1D\x4D\xF2\xF4\x2C\x38\x76\x57\xF5\x13\x23\xD0\xF3\xE9\x2D\x79\x4B\xFF\x1A\x23\xD6\xF3\xE9\x23\x7B\x5D\xF7\xD2\xB6\xDA\x3D\xCC\x79\xF6\x20\xDA\xF2\xBA\x3B\x7F\x6E\xFC\xD2\x27\xA4\x41\x0E\x89\xED\xA2\x1A\xE9\x07\xDA\x3D\x12\x83\xF6\xD0\x1A\xF7\x66\xF9\x2F\x23\x83\xF7\x03\x1A\xF7\x54\xF9\x2F\x38\x84\xF8\x02\x1A\xF7\x5A\xF9\x2E\x4E\x8A\xF8\x3B\xA5\xF8\xC0\x3A\x85\x78\xF1\x1B\x35\xDF\xD2\x03\x3E\x85\x95\xF3\x1B\x3D\xD0\xF6\xF9\x21\x86\xE7\xC0\x27\x3D\xD1\xF8\x00\x37\x86\x9D\xE8\x1D\x3D\xD7\xF8\x00\x3A\xE7\xA7\xF2\x1A\x3D\xDD\xF8\x1D\xCF\x89\x47\xB2\x1A\xA4\xEB\xF7\x14\x45\x00\x9F\x8C\xE7\xB5\xF4\xFA\x2E\x38\x00\xB2\xF1\x23\xB5\xFA\xFA\x2E\x3D\x00\xBF\xF4\x21\xB5\xF0\xFB\x00\x32\x01\xC5\xFA\x23\x66\xD5\xFB\x03\x37\x01\x9F\x8E\xF9\xD5\x11\x8E\x7C\xE8\x1D\x18\x0F\x89\xB7\xA3\x59\xE1\x81\xE8\xBE\x2A\x01\xD8\xFC\x9C\x9C\xD5\xE8\x31\x2C\x01\xDF",
			"\xFB\xC1\xAC\x81\x8E\xD1\xE1\x2E\x1E\x05\xFE\xED\xCA\xA2\x3D\xAD\xD1\xC0\x30\x02\xEC\xF2\xA4\xB0\x91\x8E\xAF\xE1\x2E\x22\x03\xFF\x5B\x10\x16\xE1\x8D\xF4\x03\x34\x02\xFA\x7E\x2B\x3C\x7E\x87\x66\x36\x26\x01\x00\x81\x54\xE8\x49\xD5\x40\x1E\x14\x07\x00\xAF\x78\x67\x75\x6B\x03\x1A\x05\x07\x81\xA6\x7C\x8A\x4B\x6A\xF4\x6E\x19\x2C\x07\x13\x77\x7F\xD9\x0B\xD4\x3C\x7E\x88\x10\x01\x9F\x41\xFD\x5C\x81\xDC\x6E\x44\x36\x01\x08\x91\x11\x4B\x68\xF9\x6E\x18\x1E\x07\x02\x94\x13\x70\x6B\x6A\x03\x1A\x08\x11\x7F\x18\x18\xEC\x3D\x6B\xC0\x03\x02\x33\x84\x42\x3D\x6A\xB3\x60\xEE\x39\x82\x8E\x1D\x75\xE1\x43\x60\x05\x02\x1F\x88\x26\x75\x6B\x05\x82\x11\x46\x01\xF7\x71\x11\xBA\x6E\x01\xB1\x11\x12\x0B\x7E\x45\x84\x04\x83\x18\x27\x00\x05\xED\x11\x5D\x6A\x81\x22\x13\x0A\x15\x82\x38\x15\xD7\x35\x6B\xC0\x18\x02\x44\x85\x4D\x39\x6A\xD4\x67\x32\x59\x03\x01\x98\x0E\xAD\x6C\xB8\x40\x1F\x2D\x01\x06\xF0\x11\x71\x61\x08\xB9\x76\x6C\x1C\x03\x36\x81\x27\x6F\x80\x00\x00\x01\xC0\x1D\x0B\x34\x82\xEC\x0C\xDC\x09\x09\x1C\x9A\x1D\x5E\x03\x0F\xA2\x0D\x3F\x82",
			"\x10\x0C\x6F\xC0\x1F\x02\x1A\x81\x46\x05\x15\x84\x0D\x07\xE6\x1B\x18\x02\x84\xB1\x08\x0F\x89\x09\x45\x86\x36\x64\x00\x24\x93\x0D\x12\x0E\x20\x3F\x75\x93\x15\x06\x67\x82\x68\x00\x15\x09\x0E\x53\x27\x19\x33\x0A\x04\x94\x13\x26\x86\x08\xA0\x86\x6C\x2A\x03\x4B\x8F\x1A\x14\x09\x42\x1B\x15\x27\x1B\x0D\x1E\x85\xD8\x00\x0B\x86\x09\xB5\x07\x19\x6D\x04\x15\x90\x0E\x14\x0A\x10\x27\x86\xEE\x0E\x03\x07\x87\xEB\x4A\x08\x5E\x89\x10\x44\x76\xD9\x10\x03\xBA\x85\x3A\x1B\x6E\x4D\x80\x3C\x71\x03\x01\x8F\x69\xAC\x43\x19\x83\x08\x63\x8A\x3B\x73\x01\x32\x9C\x0E\xD4\x82\x20\x39\x15\x93\x14\x07\x09\x84\x85\x17\x85\x06\x0C\x18\xA6\x1A\x3C\x07\x0D\xB5\x0A\x45\x09\x08\x05\x1F\x64\x39\x03\x59\x83\x1B\x4A\x76\x41\x0D\x01\xC0\x1B\x0F\x25\x84\x1D\x19\x0E\x86\x0A\x3B\x9A\x1D\x7E\x05\x1C\x97\x08\x85\x02\x03\x40\x1F\x1F\x0C\x87\xAF\x0D\x1F\x89\x08\xA3\x17\x32\x01\x06\x3E\x89\x08\x2A\x18\x1D\x80\x1E\x41\x07\x00\xFA\x78\x2B\x49\x88\x06\x0C\x68\x27\x18\x42\x07\x10\xE8\x6E\x42\x15\x87\xBA\x1D\x10\x07\x81\x9B\x4C\x8A\x4F\x76\x40\x12\x88\x66\x1F\x10",
			"\x15\x89\x81\x00\x12\x83\x09\x0C\x00\x1E\x88\x06\x1B\xBA\x10\x82\x86\x10\x10\x8A\xEE\x0C\x04\x23\x8A\x20\x1A\x09\x84\x09\x35\x27\x19\x23\x00\x88\xD0\x0D\x26\x86\x08\xBD\x17\x32\x0F\x05\x4C\x81\x08\xD6\x75\xFD\x54\x20\x48\x07\x00\xB5\x68\x2B\x41\x8A\x17\x6F\x64\x12\x05\x03\x8D\xF9\x0A\x08\x52\x94\x6F\x4E\x24\x12\x07\x81\xDA\x77\x14\xC0\x76\xD9\x16\x04\x07\x86\xAC\x55\x8B\xB7\x77\x32\x18\x07\x01\x86\x52\x06\x0F\x29\xB4\x60\xE0\x1A\x09\x07\x82\x05\x8E\x8A\x18\x6F\x64\x1C\x05\x03\x83\xDC\x5B\x8B\x79\x7A\x1D\x9E\x07\x00\x88\x76\xB7\x88\xD0\x14\x20\x28\x07\x80\x7D\x6C\x2E\xAA\x6A\xE0\x12\x0A\x07\x81\xAF\x6C\x45\x3B\x02\x21\x38\x00\xE0\x14\x0A\x2A\x88\x9A\x0F\x6F\x09\x09\x30\xA7\x18\x54\x0F\x13\x80\x00\x4F\x81\x8B\xC0\x19\x15\x0D\x8D\xC2\x16\x10\x11\x1F\xC9\x0A\x05\x38\x8D\x3A\x1B\x76\x83\x0A\x13\xBA\x1C\x2B\x07\x80\x46\x82\x21\x1B\x8D\x81\x0F\x38\x27\x1A\x2B\x0D\x8C\xFD\x6B\x20\x1D\x8C\xED\x1F\x0A\x07\x83\x18\x8E\x7F\x00\x01\x35\x82\x09\xD2\x86\x36\x31\x05\x63\x94\x8D\x03\x09\x71\x27\x18\x59\x06\x18\xED\x12\x65\x86",
			"\x08\xA3\x8A\x7B\x36\x05\xC6\x81\xEE\x03\x09\xE9\x07\x19\xB7\x01\x33\x9C\x0F\xE2\x82\x10\x1B\x1F\xC9\x19\x05\xCA\x8D\x26\x05\x70\x83\x06\x39\x27\x1B\x2E\x13\x87\x68\x16\x39\x95\x8C\xE0\x1E\x0B\x07\x80\x63\x6C\x45\x0A\x74\x3A\x80\x1E\x60\x08\x1D\xED\x13\x71\x9B\x8E\x27\x1B\x18\x07\x81\x34\x8C\x8A\x66\x76\x41\x13\x1F\x27\x1D\x18\x11\x8E\x85\x02\x3C\x21\x7E\x13\x27\x06\x07\x86\x0E\xAC\x45\xFA\x89\xB4\x27\x19\x32\x07\x80\x8D\x80\x3D\x7C\x8E\xE7\x56\x36\x4B\x07\x01\x84\x84\x48\x7B\x20\x03\x91\x44\x76\x36\x4D\x07\x01\x94\x84\x02\x92\xED\x66\x1B\x67\x07\x00\x92\x84\x6C\x4B\x90\x63\x8F\x64\x11\x07\x03\x89\x09\x91\x93\x0A\x60\x1E\xD3\x07\x00\xA2\x85\x0B\x94\x00\xBA\x1D\x35\x07\x80\xA9\x86\x43\xA2\x65\x81\x17\x0D\x07\x82\x2F\x90\x8D\x18\x97\xAC\x40\x1F\x6C\x07\x00\xAE\x84\x6C\x56\x1E\x09\x0B\x09\x00\x1F\x6D\x05\x1E\xF0\x12\x83\x66\x08\x38\x96\x6C\x1E\x07\xC6\x80\x1F\x86\x09\x8C\x83\x18\xDF\x05\x31\xAB\x77\x81\x09\x41\x27\x18\x38\x13\x8F\x09\x0A\x0A\x22\x66\x11\x12\x0E\x07\x83\x36\x90\x4D\x52\x91\x21\x1C\x7F\x70\x14\x0E",
			"\x07\x81\x2D\x88\x4F\x59\x91\x8D\x7A\x1C\x73\x07\x00\xE2\x84\x98\x96\x8A\xBA\x18\x1D\x07\x80\x69\x80\x1B\xE1\x90\xFC\x67\x19\xEA\x07\x00\x99\x87\x04\x92\x10\x6E\x92\x40\x1B\x80\xE9\x14\x1D\x07\x80\x70\x87\x26\x9F\x93\xC9\x0E\x07\x07\x87\x1C\x98\x93\x12\x9A\x3D\x70\x07\x01\x90\x87\x93\x2E\x4E\xA5\x74\x0A\x22\x0F\x07\x83\x3D\x8D\x93\xA7\x77\x64\x34\x07\x03\x88\x11\xB0\x8F\x14\x0A\x08\xFC\x1F\x64\x36\x07\x1E\x91\x27\x14\x72\x41\x17\x94\x27\x19\x1F\x0D\x8D\x26\x96\x10\x0A\x96\x13\x3A\x07\x8D\x8F\xDD\x43\x08\x24\x27\x32\x7B\x04\x94\x86\x08\xAC\x96\x20\x0E\x25\x93\x1D\x0F\x0D\x8F\x15\x29\x08\x45\x92\x77\x3E\x07\x03\x87\x30\x30\x4F\xAD\x86\x08\xA4\x92\x77\x3C\x64\x51\x67\x12\x93\x2F\xAF\x83\x08\x7F\x27\x64\x02\x01\x00\x78\x1D\x74\x74\x93\x80\x1E\x03\x05\xCD\x49\x08\x81\x80\x9B\x4E\x96\x40\x09\x96\x66\x1D\x00\x0C\x96\xD1\x05\xE2\x48\x94\xF0\x06\x00\xDB\x91\x36\x18\x97\x81\x06\x44\x27\x1B\x01\x10\x45\xB3\x79\x36\x33\x94\x83\x07\x2C\x99\x75\xB8\x93\x0D\xA0\x26\x20\x2A\x27\x93\x1D\x00\x52\x96\x8E\x19\x77\x42\x8E\x89\x0F",
			"\x00\x7B\x93\x10\x2E\x88\x6C\x98\x97\x49\x8E\x6C\x11\x00\x7E\x92\x10\x1E\x88\x9D\x81\x08\x00\x98\x2A\x83\x19\x09\x04\x30\x81\x09\x49\x9F\x97\x68\x92\x7B\x15\x01\x86\x90\x00\x2C\x88\x7A\x49\x98\x22\x68\x78\x17\x00\x8A\x93\x13\xB0\x4C\xC6\x80\x00\x78\x91\x5F\x19\x00\x8A\x93\x18\x93\x2F\xC7\x9E\x7F\xBE\x13\x03\x14\x99\xD5\x87\x30\x80\x03\xC7\x89\x97\x2C\x1D\x03\x14\x98\xB1\x86\xFB\x2E\x98\x34\x79\x17\x1F\x04\x62\x8A\x8C\x8F\x91\x29\xE6\x19\x08\x14\x98\x88\x88\x36\x5B\x27\x84\x08\x4B\x27\x1B\x08\x10\x45\x7C\x73\xC5\x46\x09\xA1\x95\x00\xEF\x97\x6B\x13\x97\x06\x0F\x63\x83\x19\x13\x0E\x34\xD0\x0E\x3D\x26\x08\xFE\x76\x6C\x28\x00\x8A\x98\x1D\x59\x98\x50\x20\x1E\x2A\x05\x6A\x95\x0F\x88\x29\x10\x50\x9A\xEE\x0B\x01\x14\x9F\x31\xA8\x4E\xB2\x96\x10\x2C\x2B\xC9\x0D\x01\x62\x9C\x3B\x30\x71\xB6\x90\x3C\x2E\x01\xDC\x95\x09\x6E\x9E\x20\x39\x27\x93\x1F\x02\x30\x45\xC8\x95\x0E\x41\x29\x21\x2C\x9A\xDD\x13\x03\x77\x99\x4A\x0A\x08\x5F\x92\x7B\x34\x00\x8A\x94\x19\xE8\x4D\x51\x26\x08\xD4\x92\x77\x36\x00\x8A\x9A\x1B\xB0\x4F\xE3\x86\x8E",
			"\xC0\x18\x07\x14\x99\xE0\x8D\x32\x97\x9D\x73\x80\x1E\x3A\x04\x62\xB2\x8D\xCE\x9A\x10\x31\x96\xEE\x1C\x01\x14\x98\x37\xB0\x8C\xCF\x91\x10\x5E\x9A\xF6\x1E\x01\x14\x9F\x37\xA8\x4F\x1A\x76\x10\x03\x7A\xD9\x00\x02\x86\x99\x21\x0F\x73\xDA\x90\x3C\x41\x01\xEE\x86\x08\x49\x74\x77\xA7\x18\x21\x0F\x3B\xC1\x72\x42\x16\x9D\xBA\x1B\x08\x05\x9E\x81\x0B\xE3\x42\x9E\xD9\x04\x02\xCB\x99\x20\x12\x2C\x83\x09\x38\x94\x21\x11\x14\x98\xCC\x8B\x51\x80\x01\xE9\x93\x10\x11\x9E\xF6\x07\x02\x14\x9B\x3A\xB5\x8B\xED\x9A\x10\x67\x8E\xEE\x09\x02\x14\x99\x3C\xA3\x9E\xEE\x9F\x39\xA7\x1B\x12\x14\x98\xEE\x8B\x7D\xA5\x9C\xE0\x1D\x04\x14\x99\x8C\x84\x46\xEC\x9D\x75\x80\x1F\x27\x04\x31\xBF\x92\xFC\x89\x08\x69\x83\x60\x11\x02\x8A\x9B\x24\xB0\x8F\x98\x63\x08\xD5\x9E\x89\x13\x02\x8A\x99\x29\xA2\x67\x01\xA2\x08\xDE\x9C\x82\x15\x02\x8A\x90\x2A\x8E\xA1\xF9\x80\x1E\x57\x04\x62\x81\x97\x55\x72\x10\x0F\xA1\x40\x1A\x8E\xBA\x19\x0B\x14\x99\x72\x96\x41\x89\x0A\xE9\x9A\x1E\x5B\x04\x62\xAD\x96\xED\x9E\x41\x80\x02\xEB\x94\x20\x5D\x04\x62\x9D\x96\x0E\xA1\x10\x2D",
			"\xA1\x00\xB7\x25\x14\x9B\x5D\xA8\x4E\x2A\x76\x10\x18\x2F\xC9\x01\x03\x5C\x9A\x34\x0F\x78\x04\xA0\x3C\x63\x00\xC5\x91\x97\xDE\x61\x21\x03\xA2\x08\xA0\x3C\x65\x00\xC5\x8C\x9A\x49\xA6\x20\x0B\xA3\x80\x06\x3E\xDA\x1F\x19\x14\x98\x57\x99\x8A\x83\x09\x29\xA0\x00\x20\xA2\xF6\x09\x03\x14\x9B\x70\x89\x68\x25\xA3\x3F\xB1\x84\xC5\x81\x9C\xF9\x94\x8B\xAF\xA0\x27\x2D\x06\x14\x98\xED\x9A\xA2\x02\x0C\x8B\xB7\xA1\x70\x1F\x06\x14\x99\xC2\x63\x9F\x6A\x76\x20\x3E\x2D\x93\x11\x07\x7E\x99\x8C\x19\xA3\x44\xA7\x64\x35\x02\x8A\x99\x3F\xB0\x62\x42\x00\xA4\x4C\xA7\x64\x37\x02\x8A\x9C\x43\xF0\xA1\x40\x08\xA4\x54\xA0\x78\x39\x02\x8A\x90\x49\x86\xA5\x42\x15\xA4\x5E\xA4\x82\x3B\x02\x8A\x96\x5C\x76\x8D\x25\xA7\xA1\x14\x25\x0F\x14\x98\xE6\x2E\x49\x8A\x0B\x1A\xA3\x18\x7F\x04\x62\xAD\x2F\x52\xA0\x40\xC0\x1D\x20\x14\x98\x0B\x33\x83\x76\x73\x81\x0B\x47\xE6\x1B\x20\x1E\xA3\x14\x13\x96\x82\x09\x04\xA3\x30\x07\x04\xC5\x81\x79\xF9\x92\x97\x81\x09\x08\xAE\x44\x09\x04\xC5\x91\x31\xF6\x8A\x98\x80\x01\x2A\xA4\x41\x0B\x04\xC5\x87\x79\xC1\xA2\x21\x19\xA4",
			"\x27\x2D\x08\x14\x99\x9B\x29\xA6\x65\xA6\x6C\x0F\x04\x8A\x9C\xF2\x51\xA5\x42\x07\xA5\xBE\x11\x12\x14\x99\x44\x38\x4D\xAD\xA7\xC9\x13\x04\x14\x9A\xE6\x62\x64\xE2\x26\xD0\x0B\x09\x3B\xAF\xA7\xF0\xA1\x9E\xB2\xA7\x79\xA4\x4F\xF5\xA5\x96\x40\x55\xFB\x40\x9F\x8E\x66\x51\x63\x2C\x9B\x62\x25\xB6\x8F\xB3\x56\x3E\xA0\x99\x9A\x03\xE9\x4E\x52\x41\xA4\xA8\x08\xAC\x50\xBB\x7E\x99\x00\xA5\x50\x50\xEF\x55\x75\x0F\xAD\x26\x11\xA9\x88\x90\x15\x88\x83\x42\x15\x4A\x16\xAD\xA2\x98\xA8\x8C\xA3\xE0\x02\x70\x51\x1D\xA8\x20\xA8\xD0\x75\x09\xA6\x70\x00\x7E\x7C\x49\xA7\xA9\x23\xAE\xEB\x6A\xA8\x99\x03\xD2\x24\x6B\x4A\xBC\x8A\x2A\x6D\xA5\x4B\x09\x97\x60\xD3\x35\x08\x4D\xB4\xA9\x7A\x78\x00\x3A\x7B\x7F\x09\x53\xBD\xA9\x4D\x1E\xA9\x33\x6F\x85\x44\x52\x99\x07\x93\x43\xA9\xDD\x71\x7C\x03\x0D\xA6\x49\x58\xA2\x0A\x54\xCD\xA9\x4D\x0E\xAA\x43\x69\x21\x36\x81\x9E\x6E\xD3\x51\xAA\x41\x14\xAA\x54\xAD\xF6\x40\x00\xE7\x7A\x55\xDA\xAA\x59\x7E\x6B\x44\x0F\xAB\x9F\xAB\x9A\x00",
		};
		vl::glr::DecompressSerializedData(compressed, true, dataSolidRows, dataRows, dataBlock, dataRemain, outputStream);
	}

	const wchar_t* ParserRuleName(vl::vint index)
	{
		static const wchar_t* results[] = {
			L"RType",
			L"RAttributeParameter",
			L"RAttribute",
			L"REnumMember",
			L"REnum",
			L"RUnionMember",
			L"RUnion",
			L"RStructMember",
			L"RStructBody",
			L"RStruct",
			L"RMessageRequest",
			L"RMessageResponse",
			L"RMessage",
			L"REventRequest",
			L"REvent",
			L"RDeclDetail",
			L"RDecl",
			L"Schema",
		};
		return results[index];
	}

	const wchar_t* ParserStateLabel(vl::vint index)
	{
		static const wchar_t* results[] = {
			L"[0][RType] BEGIN ",
			L"[1][RType] END [ENDING]",
			L"[2][RType]< \"binary\" @ >",
			L"[3][RType]< \"bool\" @ >",
			L"[4][RType]< \"char\" @ >",
			L"[5][RType]< \"color\" @ >",
			L"[6][RType]< \"double\" @ >",
			L"[7][RType]< \"float\" @ >",
			L"[8][RType]< \"int\" @ >",
			L"[9][RType]< \"key\" @ >",
			L"[10][RType]< \"string\" @ >",
			L"[11][RType]< NAME \"[\" \".\" @ NAME \"]\" >",
			L"[12][RType]< NAME \"[\" \".\" NAME \"]\" @ >",
			L"[13][RType]< NAME \"[\" \".\" NAME @ \"]\" >",
			L"[14][RType]< NAME \"[\" @ \".\" NAME \"]\" >",
			L"[15][RType]< RType \"?\" @ >",
			L"[16][RType]< RType \"[\" \"]\" @ >",
			L"[17][RType]< RType \"[\" @ \"]\" >",
			L"[18][RType]< RType \"[\" @ RType \"]\" >",
			L"[19][RType]< RType \"[\" RType \"]\" @ >",
			L"[20][RType]< RType \"[\" RType @ \"]\" >",
			L"[21][RType]< RType @ \"?\" >",
			L"[22][RType]< RType @ \"[\" \"]\" >",
			L"[23][RType]< RType @ \"[\" RType \"]\" >",
			L"[24][RType]{{< NAME @ \"[\" \".\" NAME \"]\" > ; < NAME @ >}}",
			L"[25][RAttribute] BEGIN ",
			L"[26][RAttribute] END [ENDING]",
			L"[27][RAttribute]< \"[\" @ ATT_NAME [ \"(\" ( CPP_NAME ) \")\" ] \"]\" >",
			L"[28][RAttribute]< \"[\" ATT_NAME @ [ \"(\" ( CPP_NAME ) \")\" ] \"]\" >",
			L"[29][RAttribute]< \"[\" ATT_NAME [ \"(\" ( CPP_NAME ) \")\" @ ] \"]\" >",
			L"[30][RAttribute]< \"[\" ATT_NAME [ \"(\" ( CPP_NAME ) \")\" ] \"]\" @ >",
			L"[31][RAttribute]< \"[\" ATT_NAME [ \"(\" ( CPP_NAME @ ) \")\" ] \"]\" >",
			L"[32][RAttribute]< \"[\" ATT_NAME [ \"(\" @ ( CPP_NAME ) \")\" ] \"]\" >",
			L"[33][REnumMember] BEGIN ",
			L"[34][REnumMember] END [ENDING]",
			L"[35][REnumMember]< NAME \",\" @ >",
			L"[36][REnumMember]< NAME @ \",\" >",
			L"[37][REnum] BEGIN ",
			L"[38][REnum] END [ENDING]",
			L"[39][REnum]< \"enum\" @ NAME \"{\" { REnumMember } \"}\" >",
			L"[40][REnum]< \"enum\" NAME \"{\" @ { REnumMember } \"}\" >",
			L"[41][REnum]< \"enum\" NAME \"{\" { REnumMember @ } \"}\" >",
			L"[42][REnum]< \"enum\" NAME \"{\" { REnumMember } \"}\" @ >",
			L"[43][REnum]< \"enum\" NAME @ \"{\" { REnumMember } \"}\" >",
			L"[44][RUnionMember] BEGIN ",
			L"[45][RUnionMember] END [ENDING]",
			L"[46][RUnionMember]< NAME \",\" @ >",
			L"[47][RUnionMember]< NAME @ \",\" >",
			L"[48][RUnion] BEGIN ",
			L"[49][RUnion] END [ENDING]",
			L"[50][RUnion]< \"union\" @ NAME \"{\" { RUnionMember } \"}\" >",
			L"[51][RUnion]< \"union\" NAME \"{\" @ { RUnionMember } \"}\" >",
			L"[52][RUnion]< \"union\" NAME \"{\" { RUnionMember @ } \"}\" >",
			L"[53][RUnion]< \"union\" NAME \"{\" { RUnionMember } \"}\" @ >",
			L"[54][RUnion]< \"union\" NAME @ \"{\" { RUnionMember } \"}\" >",
			L"[55][RStructMember] BEGIN ",
			L"[56][RStructMember] END [ENDING]",
			L"[57][RStructMember]< \"var\" @ NAME \":\" RType \";\" >",
			L"[58][RStructMember]< \"var\" NAME \":\" @ RType \";\" >",
			L"[59][RStructMember]< \"var\" NAME \":\" RType \";\" @ >",
			L"[60][RStructMember]< \"var\" NAME \":\" RType @ \";\" >",
			L"[61][RStructMember]< \"var\" NAME @ \":\" RType \";\" >",
			L"[62][RStructBody] BEGIN ",
			L"[63][RStructBody] END [ENDING]",
			L"[64][RStructBody]< NAME \"{\" @ { RStructMember } \"}\" >",
			L"[65][RStructBody]< NAME \"{\" { RStructMember @ } \"}\" >",
			L"[66][RStructBody]< NAME \"{\" { RStructMember } \"}\" @ >",
			L"[67][RStructBody]< NAME @ \"{\" { RStructMember } \"}\" >",
			L"[68][RStruct] BEGIN ",
			L"[69][RStruct] END [ENDING]",
			L"[70][RStruct]<! \"class\" !RStructBody @ !>",
			L"[71][RStruct]<! \"class\" @ !RStructBody !>",
			L"[72][RStruct]<! \"struct\" !RStructBody @ !>",
			L"[73][RStruct]<! \"struct\" @ !RStructBody !>",
			L"[74][RMessageRequest] BEGIN ",
			L"[75][RMessageRequest] END [ENDING]",
			L"[76][RMessageRequest]< \"request\" \":\" @ RType \";\" >",
			L"[77][RMessageRequest]< \"request\" \":\" RType \";\" @ >",
			L"[78][RMessageRequest]< \"request\" \":\" RType @ \";\" >",
			L"[79][RMessageRequest]< \"request\" @ \":\" RType \";\" >",
			L"[80][RMessageResponse] BEGIN ",
			L"[81][RMessageResponse] END [ENDING]",
			L"[82][RMessageResponse]< \"response\" \":\" @ RType \";\" >",
			L"[83][RMessageResponse]< \"response\" \":\" RType \";\" @ >",
			L"[84][RMessageResponse]< \"response\" \":\" RType @ \";\" >",
			L"[85][RMessageResponse]< \"response\" @ \":\" RType \";\" >",
			L"[86][RMessage] BEGIN ",
			L"[87][RMessage] END [ENDING]",
			L"[88][RMessage]< \"message\" @ NAME \"{\" [ RMessageRequest ] [ RMessageResponse ] \"}\" >",
			L"[89][RMessage]< \"message\" NAME \"{\" @ [ RMessageRequest ] [ RMessageResponse ] \"}\" >",
			L"[90][RMessage]< \"message\" NAME \"{\" [ RMessageRequest @ ] [ RMessageResponse ] \"}\" >",
			L"[91][RMessage]< \"message\" NAME \"{\" [ RMessageRequest ] [ RMessageResponse @ ] \"}\" >",
			L"[92][RMessage]< \"message\" NAME \"{\" [ RMessageRequest ] [ RMessageResponse ] \"}\" @ >",
			L"[93][RMessage]< \"message\" NAME @ \"{\" [ RMessageRequest ] [ RMessageResponse ] \"}\" >",
			L"[94][REventRequest] BEGIN ",
			L"[95][REventRequest] END [ENDING]",
			L"[96][REventRequest]< \"request\" \":\" @ RType \";\" >",
			L"[97][REventRequest]< \"request\" \":\" RType \";\" @ >",
			L"[98][REventRequest]< \"request\" \":\" RType @ \";\" >",
			L"[99][REventRequest]< \"request\" @ \":\" RType \";\" >",
			L"[100][REvent] BEGIN ",
			L"[101][REvent] END [ENDING]",
			L"[102][REvent]< \"event\" @ NAME \"{\" [ REventRequest ] \"}\" >",
			L"[103][REvent]< \"event\" NAME \"{\" @ [ REventRequest ] \"}\" >",
			L"[104][REvent]< \"event\" NAME \"{\" [ REventRequest @ ] \"}\" >",
			L"[105][REvent]< \"event\" NAME \"{\" [ REventRequest ] \"}\" @ >",
			L"[106][REvent]< \"event\" NAME @ \"{\" [ REventRequest ] \"}\" >",
			L"[107][RDeclDetail] BEGIN ",
			L"[108][RDeclDetail] END [ENDING]",
			L"[109][RDeclDetail]<! !REnum @ !>",
			L"[110][RDeclDetail]<! !REvent @ !>",
			L"[111][RDeclDetail]<! !RMessage @ !>",
			L"[112][RDeclDetail]<! !RStruct @ !>",
			L"[113][RDeclDetail]<! !RUnion @ !>",
			L"[114][RDecl] BEGIN ",
			L"[115][RDecl] END [ENDING]",
			L"[116][RDecl]<! { RAttribute @ } !RDeclDetail !>",
			L"[117][RDecl]<! { RAttribute } !RDeclDetail @ !>",
			L"[118][Schema] BEGIN ",
			L"[119][Schema] END [ENDING]",
			L"[120][Schema]< RDecl @ { RDecl } >",
			L"[121][Schema]< RDecl { RDecl @ } >",
		};
		return results[index];
	}

	Parser::Parser()
		: vl::glr::ParserBase<GuiRemoteProtocolTokens, ParserStates, GuiRemoteProtocolAstInsReceiver>(&GuiRemoteProtocolTokenDeleter, &GuiRemoteProtocolLexerData, &GuiRemoteProtocolParserData)
	{
	}

	vl::WString Parser::GetClassName(vl::vint32_t classIndex) const
	{
		return vl::WString::Unmanaged(GuiRemoteProtocolTypeName((GuiRemoteProtocolClasses)classIndex));
	}

	vl::vint32_t Parser::FindCommonBaseClass(vl::vint32_t class1, vl::vint32_t class2) const
	{
		return -1;
	}

	vl::Ptr<vl::presentation::remoteprotocol::GuiRpSchema> Parser::ParseSchema(const vl::WString& input, vl::vint codeIndex) const
	{
		 return ParseWithString<vl::presentation::remoteprotocol::GuiRpSchema, ParserStates::Schema>(input, this, codeIndex);
	}

	vl::Ptr<vl::presentation::remoteprotocol::GuiRpSchema> Parser::ParseSchema(vl::collections::List<vl::regex::RegexToken>& tokens, vl::vint codeIndex) const
	{
		 return ParseWithTokens<vl::presentation::remoteprotocol::GuiRpSchema, ParserStates::Schema>(tokens, this, codeIndex);
	}
}


/***********************************************************************
.\REMOTEPROTOCOL\GENERATED\GUIREMOTEPROTOCOL_ASSEMBLER.CPP
***********************************************************************/
/***********************************************************************
This file is generated by: Vczh Parser Generator
From parser definition:GuiRemoteProtocol
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/


namespace vl::presentation::remoteprotocol
{

/***********************************************************************
GuiRemoteProtocolAstInsReceiver : public vl::glr::AstInsReceiverBase
***********************************************************************/

	vl::Ptr<vl::glr::ParsingAstBase> GuiRemoteProtocolAstInsReceiver::CreateAstNode(vl::vint32_t type)
	{
		auto cppTypeName = GuiRemoteProtocolCppTypeName((GuiRemoteProtocolClasses)type);
		switch((GuiRemoteProtocolClasses)type)
		{
		case GuiRemoteProtocolClasses::ArrayMapType:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpArrayMapType);
		case GuiRemoteProtocolClasses::ArrayType:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpArrayType);
		case GuiRemoteProtocolClasses::Attribute:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpAttribute);
		case GuiRemoteProtocolClasses::EnumDecl:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpEnumDecl);
		case GuiRemoteProtocolClasses::EnumMember:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpEnumMember);
		case GuiRemoteProtocolClasses::EventDecl:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpEventDecl);
		case GuiRemoteProtocolClasses::EventRequest:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpEventRequest);
		case GuiRemoteProtocolClasses::MapType:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpMapType);
		case GuiRemoteProtocolClasses::MessageDecl:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpMessageDecl);
		case GuiRemoteProtocolClasses::MessageRequest:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpMessageRequest);
		case GuiRemoteProtocolClasses::MessageResponse:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpMessageResponse);
		case GuiRemoteProtocolClasses::OptionalType:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpOptionalType);
		case GuiRemoteProtocolClasses::PrimitiveType:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpPrimitiveType);
		case GuiRemoteProtocolClasses::ReferenceType:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpReferenceType);
		case GuiRemoteProtocolClasses::Schema:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpSchema);
		case GuiRemoteProtocolClasses::StructDecl:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpStructDecl);
		case GuiRemoteProtocolClasses::StructMember:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpStructMember);
		case GuiRemoteProtocolClasses::UnionDecl:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpUnionDecl);
		case GuiRemoteProtocolClasses::UnionMember:
			return vl::Ptr(new vl::presentation::remoteprotocol::GuiRpUnionMember);
		default:
			return vl::glr::AssemblyThrowCannotCreateAbstractType(type, cppTypeName);
		}
	}

	void GuiRemoteProtocolAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::Ptr<vl::glr::ParsingAstBase> value)
	{
		auto cppFieldName = GuiRemoteProtocolCppFieldName((GuiRemoteProtocolFields)field);
		switch((GuiRemoteProtocolFields)field)
		{
		case GuiRemoteProtocolFields::ArrayType_element:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpArrayType::element, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::Declaration_attributes:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpDeclaration::attributes, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::EnumDecl_members:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpEnumDecl::members, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::EventDecl_request:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpEventDecl::request, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::EventRequest_type:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpEventRequest::type, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::MapType_element:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpMapType::element, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::MapType_keyType:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpMapType::keyType, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::MessageDecl_request:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpMessageDecl::request, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::MessageDecl_response:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpMessageDecl::response, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::MessageRequest_type:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpMessageRequest::type, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::MessageResponse_type:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpMessageResponse::type, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::OptionalType_element:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpOptionalType::element, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::Schema_declarations:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpSchema::declarations, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::StructDecl_members:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpStructDecl::members, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::StructMember_type:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpStructMember::type, object, field, value, cppFieldName);
		case GuiRemoteProtocolFields::UnionDecl_members:
			return vl::glr::AssemblerSetObjectField(&vl::presentation::remoteprotocol::GuiRpUnionDecl::members, object, field, value, cppFieldName);
		default:
			return vl::glr::AssemblyThrowFieldNotObject(field, cppFieldName);
		}
	}

	void GuiRemoteProtocolAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, const vl::regex::RegexToken& token, vl::vint32_t tokenIndex)
	{
		auto cppFieldName = GuiRemoteProtocolCppFieldName((GuiRemoteProtocolFields)field);
		switch((GuiRemoteProtocolFields)field)
		{
		case GuiRemoteProtocolFields::ArrayMapType_element:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::remoteprotocol::GuiRpArrayMapType::element, object, field, token, tokenIndex, cppFieldName);
		case GuiRemoteProtocolFields::ArrayMapType_keyField:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::remoteprotocol::GuiRpArrayMapType::keyField, object, field, token, tokenIndex, cppFieldName);
		case GuiRemoteProtocolFields::Attribute_cppType:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::remoteprotocol::GuiRpAttribute::cppType, object, field, token, tokenIndex, cppFieldName);
		case GuiRemoteProtocolFields::Attribute_name:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::remoteprotocol::GuiRpAttribute::name, object, field, token, tokenIndex, cppFieldName);
		case GuiRemoteProtocolFields::Declaration_name:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::remoteprotocol::GuiRpDeclaration::name, object, field, token, tokenIndex, cppFieldName);
		case GuiRemoteProtocolFields::EnumMember_name:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::remoteprotocol::GuiRpEnumMember::name, object, field, token, tokenIndex, cppFieldName);
		case GuiRemoteProtocolFields::ReferenceType_name:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::remoteprotocol::GuiRpReferenceType::name, object, field, token, tokenIndex, cppFieldName);
		case GuiRemoteProtocolFields::StructMember_name:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::remoteprotocol::GuiRpStructMember::name, object, field, token, tokenIndex, cppFieldName);
		case GuiRemoteProtocolFields::UnionMember_name:
			return vl::glr::AssemblerSetTokenField(&vl::presentation::remoteprotocol::GuiRpUnionMember::name, object, field, token, tokenIndex, cppFieldName);
		default:
			return vl::glr::AssemblyThrowFieldNotToken(field, cppFieldName);
		}
	}

	void GuiRemoteProtocolAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::vint32_t enumItem, bool weakAssignment)
	{
		auto cppFieldName = GuiRemoteProtocolCppFieldName((GuiRemoteProtocolFields)field);
		switch((GuiRemoteProtocolFields)field)
		{
		case GuiRemoteProtocolFields::PrimitiveType_type:
			return vl::glr::AssemblerSetEnumField(&vl::presentation::remoteprotocol::GuiRpPrimitiveType::type, object, field, enumItem, weakAssignment, cppFieldName);
		case GuiRemoteProtocolFields::StructDecl_type:
			return vl::glr::AssemblerSetEnumField(&vl::presentation::remoteprotocol::GuiRpStructDecl::type, object, field, enumItem, weakAssignment, cppFieldName);
		default:
			return vl::glr::AssemblyThrowFieldNotEnum(field, cppFieldName);
		}
	}

	const wchar_t* GuiRemoteProtocolTypeName(GuiRemoteProtocolClasses type)
	{
		const wchar_t* results[] = {
			L"ArrayMapType",
			L"ArrayType",
			L"Attribute",
			L"Declaration",
			L"EnumDecl",
			L"EnumMember",
			L"EventDecl",
			L"EventRequest",
			L"MapType",
			L"MessageDecl",
			L"MessageRequest",
			L"MessageResponse",
			L"OptionalType",
			L"PrimitiveType",
			L"ReferenceType",
			L"Schema",
			L"StructDecl",
			L"StructMember",
			L"Type",
			L"UnionDecl",
			L"UnionMember",
		};
		vl::vint index = (vl::vint)type;
		return 0 <= index && index < 21 ? results[index] : nullptr;
	}

	const wchar_t* GuiRemoteProtocolCppTypeName(GuiRemoteProtocolClasses type)
	{
		const wchar_t* results[] = {
			L"vl::presentation::remoteprotocol::GuiRpArrayMapType",
			L"vl::presentation::remoteprotocol::GuiRpArrayType",
			L"vl::presentation::remoteprotocol::GuiRpAttribute",
			L"vl::presentation::remoteprotocol::GuiRpDeclaration",
			L"vl::presentation::remoteprotocol::GuiRpEnumDecl",
			L"vl::presentation::remoteprotocol::GuiRpEnumMember",
			L"vl::presentation::remoteprotocol::GuiRpEventDecl",
			L"vl::presentation::remoteprotocol::GuiRpEventRequest",
			L"vl::presentation::remoteprotocol::GuiRpMapType",
			L"vl::presentation::remoteprotocol::GuiRpMessageDecl",
			L"vl::presentation::remoteprotocol::GuiRpMessageRequest",
			L"vl::presentation::remoteprotocol::GuiRpMessageResponse",
			L"vl::presentation::remoteprotocol::GuiRpOptionalType",
			L"vl::presentation::remoteprotocol::GuiRpPrimitiveType",
			L"vl::presentation::remoteprotocol::GuiRpReferenceType",
			L"vl::presentation::remoteprotocol::GuiRpSchema",
			L"vl::presentation::remoteprotocol::GuiRpStructDecl",
			L"vl::presentation::remoteprotocol::GuiRpStructMember",
			L"vl::presentation::remoteprotocol::GuiRpType",
			L"vl::presentation::remoteprotocol::GuiRpUnionDecl",
			L"vl::presentation::remoteprotocol::GuiRpUnionMember",
		};
		vl::vint index = (vl::vint)type;
		return 0 <= index && index < 21 ? results[index] : nullptr;
	}

	const wchar_t* GuiRemoteProtocolFieldName(GuiRemoteProtocolFields field)
	{
		const wchar_t* results[] = {
			L"ArrayMapType::element",
			L"ArrayMapType::keyField",
			L"ArrayType::element",
			L"Attribute::cppType",
			L"Attribute::name",
			L"Declaration::attributes",
			L"Declaration::name",
			L"EnumDecl::members",
			L"EnumMember::name",
			L"EventDecl::request",
			L"EventRequest::type",
			L"MapType::element",
			L"MapType::keyType",
			L"MessageDecl::request",
			L"MessageDecl::response",
			L"MessageRequest::type",
			L"MessageResponse::type",
			L"OptionalType::element",
			L"PrimitiveType::type",
			L"ReferenceType::name",
			L"Schema::declarations",
			L"StructDecl::members",
			L"StructDecl::type",
			L"StructMember::name",
			L"StructMember::type",
			L"UnionDecl::members",
			L"UnionMember::name",
		};
		vl::vint index = (vl::vint)field;
		return 0 <= index && index < 27 ? results[index] : nullptr;
	}

	const wchar_t* GuiRemoteProtocolCppFieldName(GuiRemoteProtocolFields field)
	{
		const wchar_t* results[] = {
			L"vl::presentation::remoteprotocol::GuiRpArrayMapType::element",
			L"vl::presentation::remoteprotocol::GuiRpArrayMapType::keyField",
			L"vl::presentation::remoteprotocol::GuiRpArrayType::element",
			L"vl::presentation::remoteprotocol::GuiRpAttribute::cppType",
			L"vl::presentation::remoteprotocol::GuiRpAttribute::name",
			L"vl::presentation::remoteprotocol::GuiRpDeclaration::attributes",
			L"vl::presentation::remoteprotocol::GuiRpDeclaration::name",
			L"vl::presentation::remoteprotocol::GuiRpEnumDecl::members",
			L"vl::presentation::remoteprotocol::GuiRpEnumMember::name",
			L"vl::presentation::remoteprotocol::GuiRpEventDecl::request",
			L"vl::presentation::remoteprotocol::GuiRpEventRequest::type",
			L"vl::presentation::remoteprotocol::GuiRpMapType::element",
			L"vl::presentation::remoteprotocol::GuiRpMapType::keyType",
			L"vl::presentation::remoteprotocol::GuiRpMessageDecl::request",
			L"vl::presentation::remoteprotocol::GuiRpMessageDecl::response",
			L"vl::presentation::remoteprotocol::GuiRpMessageRequest::type",
			L"vl::presentation::remoteprotocol::GuiRpMessageResponse::type",
			L"vl::presentation::remoteprotocol::GuiRpOptionalType::element",
			L"vl::presentation::remoteprotocol::GuiRpPrimitiveType::type",
			L"vl::presentation::remoteprotocol::GuiRpReferenceType::name",
			L"vl::presentation::remoteprotocol::GuiRpSchema::declarations",
			L"vl::presentation::remoteprotocol::GuiRpStructDecl::members",
			L"vl::presentation::remoteprotocol::GuiRpStructDecl::type",
			L"vl::presentation::remoteprotocol::GuiRpStructMember::name",
			L"vl::presentation::remoteprotocol::GuiRpStructMember::type",
			L"vl::presentation::remoteprotocol::GuiRpUnionDecl::members",
			L"vl::presentation::remoteprotocol::GuiRpUnionMember::name",
		};
		vl::vint index = (vl::vint)field;
		return 0 <= index && index < 27 ? results[index] : nullptr;
	}

	vl::Ptr<vl::glr::ParsingAstBase> GuiRemoteProtocolAstInsReceiver::ResolveAmbiguity(vl::vint32_t type, vl::collections::Array<vl::Ptr<vl::glr::ParsingAstBase>>& candidates)
	{
		auto cppTypeName = GuiRemoteProtocolCppTypeName((GuiRemoteProtocolClasses)type);
		return vl::glr::AssemblyThrowTypeNotAllowAmbiguity(type, cppTypeName);
	}
}


/***********************************************************************
.\REMOTEPROTOCOL\GENERATED\GUIREMOTEPROTOCOL_LEXER.CPP
***********************************************************************/
/***********************************************************************
This file is generated by: Vczh Parser Generator
From parser definition:GuiRemoteProtocol
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/


namespace vl::presentation::remoteprotocol
{
	bool GuiRemoteProtocolTokenDeleter(vl::vint token)
	{
		switch((GuiRemoteProtocolTokens)token)
		{
		case GuiRemoteProtocolTokens::SPACE:
			return true;
		default:
			return false;
		}
	}

	const wchar_t* GuiRemoteProtocolTokenId(GuiRemoteProtocolTokens token)
	{
		static const wchar_t* results[] = {
			L"VAR",
			L"ENUM",
			L"UNION",
			L"STRUCT",
			L"CLASS",
			L"MESSAGE",
			L"REQUEST",
			L"RESPONSE",
			L"EVENT",
			L"BOOLEAN",
			L"INTEGER",
			L"FLOAT",
			L"DOUBLE",
			L"STRING",
			L"CHAR",
			L"KEY",
			L"COLOR",
			L"BINARY",
			L"CPP_NAME",
			L"ATT_NAME",
			L"NAME",
			L"OPEN_BRACE",
			L"CLOSE_BRACE",
			L"OPEN_ARRAY",
			L"CLOSE_ARRAY",
			L"OPEN",
			L"CLOSE",
			L"COLON",
			L"SEMICOLON",
			L"COMMA",
			L"DOT",
			L"QUESTION",
			L"SPACE",
		};
		vl::vint index = (vl::vint)token;
		return 0 <= index && index < GuiRemoteProtocolTokenCount ? results[index] : nullptr;
	}

	const wchar_t* GuiRemoteProtocolTokenDisplayText(GuiRemoteProtocolTokens token)
	{
		static const wchar_t* results[] = {
			L"var",
			L"enum",
			L"union",
			L"struct",
			L"class",
			L"message",
			L"request",
			L"response",
			L"event",
			L"bool",
			L"int",
			L"float",
			L"double",
			L"string",
			L"char",
			L"key",
			L"color",
			L"binary",
			nullptr,
			nullptr,
			nullptr,
			L"{",
			L"}",
			L"[",
			L"]",
			L"(",
			L")",
			L":",
			L";",
			L",",
			L".",
			L"?",
			nullptr,
		};
		vl::vint index = (vl::vint)token;
		return 0 <= index && index < GuiRemoteProtocolTokenCount ? results[index] : nullptr;
	}

	const wchar_t* GuiRemoteProtocolTokenRegex(GuiRemoteProtocolTokens token)
	{
		static const wchar_t* results[] = {
			L"var",
			L"enum",
			L"union",
			L"struct",
			L"class",
			L"message",
			L"request",
			L"response",
			L"event",
			L"bool",
			L"int",
			L"float",
			L"double",
			L"string",
			L"char",
			L"key",
			L"color",
			L"binary",
			L"(::[a-zA-Z_][a-zA-Z_0-9<>]*){1,}",
			L"@[a-zA-Z_][a-zA-Z_0-9]*",
			L"[a-zA-Z_][a-zA-Z_0-9]*",
			L"/{",
			L"/}",
			L"/[",
			L"/]",
			L"/(",
			L"/)",
			L":",
			L";",
			L",",
			L".",
			L"/?",
			L"/s+",
		};
		vl::vint index = (vl::vint)token;
		return 0 <= index && index < GuiRemoteProtocolTokenCount ? results[index] : nullptr;
	}

	void GuiRemoteProtocolLexerData(vl::stream::IStream& outputStream)
	{
		static const vl::vint dataLength = 1775; // 21330 bytes before compressing
		static const vl::vint dataBlock = 256;
		static const vl::vint dataRemain = 239;
		static const vl::vint dataSolidRows = 6;
		static const vl::vint dataRows = 7;
		static const char* compressed[] = {
			"\x52\x53\x00\x00\xE7\x06\x00\x00\x6D\x00\x01\xAF\x01\x84\x81\x82\x16\x82\x09\x08\x84\x8A\x0B\x84\x81\x06\x87\x04\xA0\x11\x84\x88\x14\x88\x83\x14\x17\x84\xAC\x1A\x84\x87\x82\x82\x82\x30\x04\xB9\x04\x8A\x1C\x90\x83\x1D\x27\x84\xBC\x0A\x94\x86\x1D\x96\x82\x3F\x30\x84\x80\x23\x9C\x81\x20\x82\x5A\x04\x9B\x3A\x94\x85\x2D\x9E\x82\x5F\x40\x84\x81\x33\xA4\x82\x30\xA3\x04\xE3\x09\xA4\x84\x34\xA4\x83\x32\x4F\x84\xA6\x32\xA4\x87\x31\xAA\x82\x68\x58\x84\x89\x3B\xAC\x82\x34\xAF\x04\xEB\x21\xA4\x8C\x34\xB0\x82\x80\x01\xE8\x80\x0E\x34\x84\xB5\x81\x37\x04\xF0\x81\x90\x34\x84\xB9\x81\x38\x04\xF8\x81\x92\x34\x84\xBD\x81\x39\x04\x80\xC1\x94\x34\x84\xC1\x81\x3A\x04\x88\xC1\x96\x34\x84\xC5\x81\x3B\x04\xF8\x04\x99\x33\xCC\x82\x3C\xCB\x04\xFB\x19\xC4\x8D\x3C\xCC\x82\x0D\x9F\xA1\xC1\x80\xD1\x84\x08\x83\x0A\x04\x97\x04\x98\x04\x87\x7E\xD7\x7F\x0F\x81\x96\x0D\xDF\xD5\xD9\x0C\x82\x0E\x04\x8F\x04\x82\x0C\x83\x08\xDD\xC0\x81\x88\x04\x85\x04\x83\x04\x82\x02\x0D\x81\x9B\xDB\xE2\x85\xE7\x80\x0C\x41\xC0\x06\x02\xEC\xE4\x00\xEB\xD6\x87\x04\x84",
			"\x02\xEB\x00\x83\x00\xD5\xD2\xD0\x04\x81\x0C\xD9\xDB\xF3\xE8\xE9\xEA\xF5\xDC\x0E\xF3\xF5\xF7\xAE\xED\xC1\x8A\xF2\xF8\x03\x0C\x82\xF5\xF9\xF8\xFB\xF1\x82\xFD\xFE\xFE\x00\x3E\x71\x80\x80\x02\x85\x84\x83\x81\xFF\x49\x80\x00\x7C\x0C\x8D\x84\x7E\x7B\x0E\xA8\x75\x7F\x83\x0A\x86\x85\x84\x82\x03\x97\x8A\x84\x00\x1D\x18\x86\x85\x86\x20\x9E\x0E\x84\x84\x11\xA5\x84\x87\x82\x26\x92\x84\x89\x7C\x23\x9B\x8F\x87\x8B\x00\x9F\x0D\x88\x88\x30\xAE\x8B\x89\x8A\x38\x93\x88\x8C\x7B\x37\xB5\x84\x8F\x8C\x3E\x81\x98\x86\x44\x36\x9B\x8B\x8F\x91\xAF\x7A\x88\x92\x92\xE7\x42\x95\x90\x00\x22\x33\x81\x08\x86\x23\x00\x96\x96\x91\x48\x87\x9C\x93\x8E\x5B\x89\x97\x94\x00\x24\x1F\x9E\x93\x8F\x4F\xA3\x9D\x95\x96\x11\xA7\x96\x8A\x9A\x63\xA5\x02\x9B\x9B\x65\xB0\x90\x88\x9A\x5C\xB7\x85\x88\x9B\x72\x9F\x87\x0A\x9C\x26\x39\x9F\x94\x9D\x39\xB6\x99\x99\x8F\x7E\xB1\x9F\x91\x45\x86\xA4\x9A\xA3\x87\x80\xA9\x8A\x9B\x9D\x84\x89\xA6\x98\x80\x18\x52\xA5\xA2\xA2\x8D\xAB\x92\xA2\x83\x78\x96\xAE\xA7\xA2\x00\xAA\x07\xA6\x8F\x99\x90\xA3\x7D\x96\x9D\xA0\xAA\x83\x0A",
			"\xA3\xAD\xAF\xA7\xA3\xA5\xAF\x7B\x47\xA9\xB1\xB5\xA6\xAF\xAD\xB8\xB9\xA0\x7D\x0B\x37\xBC\xA1\x42\xAF\x00\x00\xB2\xB0\x41\xC3\xBF\xA4\xB3\xB1\xC6\x89\xB1\xB0\xB2\xCB\x8A\xB5\xB1\xB3\xD0\x8F\xB2\xB4\xB3\xBA\xA7\x88\x99\xAA\x93\xAF\xAE\xAA\xAA\xDC\x95\xBE\xB7\xB7\xE0\xA1\xB2\xBB\xB8\xE4\xA5\xB6\xBB\xB9\xE8\xA9\xBA\xBB\xBA\xEC\xAD\xBE\xBB\xBB\xF0\xB1\xB2\xBF\xBC\xF4\xB5\xB6\xBF\xBD\xF8\xB9\xBA\xBF\xBE\xFC\xBD\xBE\xBF\xBF\xAE\x5E\x40\x02\xC0\x04\xDB\xA0\xC3\xC1\xE8\xB0\xAC\xA5\xA4\xDC\x99\xBD\xC3\x97\x03\x5A\xBA\x80\xB9\x0A\xCD\x88\xB7\xB6\x0E\xD9\xCF\x9F\xB8\x15\xCC\x87\xC6\xC4\x0F\xE0\xCF\x85\x48\x89\x94\xC6\xC2\xC7\x0C\xFE\x81\x0C\xC6\x2C\xE5\xCC\xC7\xC9\xF0\x5F\xC1\xC8\xB7\x32\x2D\xC3\xCC\xA9\x2F\xF4\xAA\x95\xCA\x36\xDA\xCA\x83\x0C\xDB\xA6\xCA\xCD\x9D\x43\xDE\x91\x40\x0D\x3D\xC9\xD0\xCA\xD0\x28\x8B\x9C\xC1\x0D\x4A\xF7\xC1\xD5\xC7\xB5\x94\xDF\x7A\xCC\x3E\xDC\xB6\x0F\xD4\x33\x8C\xD7\xB4\xCF\x22\xDC\xD1\x43\x0D\x97\x9E\xD8\xA8\xD8\x52\xE1\xDF\x90\x0E\x00\xA3\x4B\xD1\xCE\x4D\xFB\xC5\xD0\x8B\x6A\xE9\xDA\xA1\x49\x75",
			"\xCC\xA0\xDF\xD7\x73\xFF\x39\xD5\xD6\x28\x79\xDD\xD7\xDE\x67\xFD\xDF\xDE\xD8\x8A\xAB\x4F\xA6\xD9\x4E\xC6\xE8\xE2\x8F\x3D\x08\xEC\xE2\xDC\x71\xFC\x82\xE3\xE5\x33\xEE\x4E\xCA\xB8\x56\xEB\x78\xD7\xE3\x88\xF1\x43\xC7\xBF\x34\x7D\xD5\xE8\x00\xA7\xE9\xE5\x4D\x40\xAA\xEC\xEB\xE8\xEA\xAF\xED\xE0\xEE\xEB\xB4\xF3\xE6\xEE\xEC\xB8\xF1\xEF\xE8\xB9\x37\x7D\xD5\x89\xEF\x95\xEF\x60\xF3\xF0\x36\x45\xF1\x40\xF1\xC7\xC6\xF0\x00\xF2\xCB\xCA\xFC\xF3\xF3\xCE\xD1\xF9\xF3\xF4\xCD\xD4\xFC\x81\xC1\x1F\x59\xF1\xF0\xC2\xDC\xE9\xBD\xE6\xB5\xE9\x47\xE8\xE6\xF8\x98\x84\xED\xE3\xF6\x7E\xE0\xEA\x82\x10\xEA\xF3\x96\xF8\xE5\x27\xA4\xF3\x9B\x10\xED\xD3\xE4\xD0\xFA\xF2\xD7\xA4\x12\xE4\xEF\xF7\xF1\xFF\xB6\x46\x0D\x7D\x11\x1B\x6C\x72\x98\x57\x68\x6D\xF9\x78\x73\x11\x65\x6D\x7F\x40\x4E\x73\x7C\x36\x68\x09\xD0\x0D\x8E\x50\x04\xAD\x7D\x3E\x49\x1C\x7D\x01\xBE\x73\x51\x07\xB6\x69\x81\x33\x6A\x08\x03\x9B\x88\x7C\x53\x78\x7F\x82\x36\x6B\x08\x01\xE1\x5F\x7B\xF0\x56\x80\x82\x89\x4C\x09\xD4\x76\x7E\x81\x13\xB0\x82\x51\x4D\x08\x87\xE8\x24\x8C\x6E\x1B\x80\x06",
			"\x09\x3A\x9F\x83\x08\xAC\x86\x80\xCF\x6F\x82\x88\x37\x84\x7C\x0D\x95\x8E\x83\x27\x01\x88\x84\x7A\x7C\x85\xE1\x3E\x85\x3E\x28\x0F\x8A\x83\x44\x9C\x83\xC2\x1E\x80\x8B\x2B\x98\x4A\x5C\x51\x04\x22\x14\x6E\x31\x8D\x80\x25\x88\x7D\x67\x8A\x3F\x19\xEB\x84\x20\x36\xA6\x8D\x8D\x70\x8F\x8E\x1C\x80\x0E\x8C\x3A\xB1\x8E\x8E\x73\x95\x8E\x1E\xF7\x8B\x8F\x39\xBC\x75\x88\xEA\x20\x79\x20\xD2\x75\x7B\x42\x90\x7C\x7A\x87\x86\x90\x21\x89\x9C\x91\x45\x80\x95\x51\x2D\x8A\x44\x17\xDE\x88\x88\xBB\x4B\x8A\x53\x93\x89\x8A\xCD\x53\x02\x4F\x4B\xA6\x87\x7F\x9A\x9B\x40\x15\x75\x74\x82\x4C\x94\x88\x40\x55\x14\x90\x08\x9E\x9D\x83\x53\xA1\x92\x51\x56\x04\x96\x14\xE7\x70\x95\x4A\x9D\x8A\x41\x57\x03\x88\xB8\x11\x9D\x49\x23\xB7\x96\x96\xBA\x9F\x58\x2F\x96\x7E\x94\x60\xB7\x80\x0B\x13\x93\x94\xFC\x2E\x81\x21\x2C\x2A\x90\x8B\xBB\x8F\x92\x24\xC5\x9F\x43\x9C\x2F\x97\x97\xAC\x9B\x88\x35\xC1\x8B\x27\x57\x99\x9E\x62\xBE\x8F\x98\xE6\x5F\x98\x65\x4C\x86\x9F\x9C\x02\x5C\x09\x32\xD9\x85\x85\x56\xB5\x97\x97\xE4\x7E\x27\xE2\x25\x9F\x92\x66\xA8\x9B\x46\x5E\x14",
			"\x90\xB9\x67\x83\x8C\x9D\x75\x8A\x8D\x37\x5D\x8C\x1E\x83\xA2\xA1\x82\xBC\x8F\xA0\x79\x88\xA0\x41\x8A\xAF\x9F\x73\x41\x2A\x8B\xDD\x71\xA1\x3D\xB4\x96\x9E\x78\xA2\x9D\x9D\xB8\x43\x9A\xD1\x5B\x97\x9B\x20\xA4\x99\x66\xE1\x9D\xA3\xA7\x60\x0D\x92\x7A\xAE\x9D\xA2\x72\x44\x2A\x48\xE7\x9F\xA3\x03\xA6\x9E\xA2\x2B\xA2\x41\x4B\xC6\x8F\xA5\x8B\xAB\x96\xA4\xDA\x8F\x9F\x97\x47\x21\xA7\x60\x9E\x5A\xA3\x74\x7C\xA3\x3D\x98\x7A\x29\xB7\x4A\x9E\x7F\x28\xBD\xA5\x40\x4D\x2B\xA5\x99\xA0\x7B\x9A\x30\xA3\xAB\xCC\x50\x2B\x86\x76\xBD\x82\xA7\x4A\xB2\xA9\x14\xD6\xA3\x8A\xAC\x8A\x53\x2A\x59\xAA\x8B\xBF\x56\x2D\x6E\xB2\x80\x06\xAC\x68\xB7\x29\x40\x69\xAB\xAC\xB5\xA7\xAE\xAD\x6C\xAF\xAD\x5B\xF3\xA2\xAF\xBA\xB1\xAF\xAE\x70\xAE\xAE\x53\xF6\x9E\xAB\xA8\xBE\xAA\x9A\x74\x40\xA9\xFA\x35\xA1\xAC\x68\x82\x98\xB0\xC4\x9D\xAC\x80\x59\x25\xB1\xBA\x7B\xAB\x9A\x8A\xAD\xB0\xB7\x5C\x23\x9F\xA3\xB5\x81\xB2\x5A\xB7\x53\x57\x46\xAC\xAA\x8A\x90\xAE\xA6\x33\x98\xA4\x38\x84\xB9\xB2\xC9\x82\xB3\x47\x62\x21\x21\x3F\xF1\x69\xB4\x00\x2D\xB2\x3D\xAF\xA9\x3D\x6B\xB3",
			"\xB3\x2D\x80\x34\xB6\xB6\xB5\xAE\xB5\x6E\xB7\xBA\xB6\xDC\xBE\xB5\xB7\xC0\xBC\xB6\x70\xBB\xB4\xB8\x88\xB6\x52\xB0\x9F\x66\xB5\x68\x96\xBC\x88\xA1\xBF\xAD\xA9\xA2\xA5\x9E\x73\x80\x45\x2C\xE5\x9C\xB0\x5C\xAD\xAB\xB5\x6D\x3C\xB0\xB7\x1B\x43\xBF\xB7\xDF\xA1\xB9\x71\xE2\xB0\xBD\xF1\xA1\xBF\xBC\xE3\xAF\xB1\x2F\xA4\xBF\xB9\xD2\xA5\x7F\x3D\xFE\x1F\x17\x6B\x6F\x15\x37\x7D\x3F\x0F\x1F\x1F\x0A\x2D\x41\x26\x35\x34\x82\x3C\xB8\x00\xFF\xA1\xC2\x7F\x83\xCD\xBF\x02\xC0\xC4\xC0\xF6\x24\x23\x94\x06\xC8\x34\xD9\x29\x33\x35\x04\x37\x37\x68\x00\x4D\x43\x80\x22\x41\x20\x32\x41\x20\x91\x07\xC6\xC0\x01\xDD\xC0\xC1\x1E\xDC\xC2\x88\xA1\xC4\xC4\x04\xCB\xC0\x00\xBF\x3A\xC1\x41\x20\xCC\xC5\x0F\xEE\xC3\xC4\x2D\xC0\x00\x43\x2F\xC6\x3B\xDE\x01\x21\xC5\x00\x00\x3F\x8B\xA5\xC1\x21\xDC\x3B\xC0\xC1\x09\x3F\xC5\x40\x36\xC0\x01\x13\xC3\x39\x20\xC9\x2F\xC4\x77\x01\x23\x3C\x21\xE2\xC7\x38\x06\xC7\xC6\x77\x01\x21\x36\x18\xC6\xC5\x3C\xD0\x3C\x34\x71\x04\x24\x3A\x03\xC4\xCA\x3B\x01\x20",
		};
		vl::glr::DecompressSerializedData(compressed, true, dataSolidRows, dataRows, dataBlock, dataRemain, outputStream);
	}
}


/***********************************************************************
.\WORKFLOWCODEGEN\GUIINSTANCELOADER_WORKFLOWCODEGEN.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace workflow;
		using namespace workflow::analyzer;
		using namespace workflow::runtime;
		using namespace reflection::description;
		using namespace collections;

		using namespace controls;
		using namespace compositions;
		using namespace templates;

/***********************************************************************
FindInstanceLoadingSource
***********************************************************************/

		template<typename TCallback>
		auto FindByTag(Ptr<GuiInstanceContext> context, GlobalStringKey namespaceName, const WString& typeName, TCallback callback)
			-> std::remove_cvref_t<decltype(callback({}).Value())>
		{
			vint index = context->namespaces.Keys().IndexOf(namespaceName);
			if (index != -1)
			{
				Ptr<GuiInstanceContext::NamespaceInfo> namespaceInfo = context->namespaces.Values()[index];
				for (auto ns : namespaceInfo->namespaces)
				{
					auto fullName = GlobalStringKey::Get(ns->prefix + typeName + ns->postfix);
					if (auto nullable = callback(fullName))
					{
						return nullable.Value();
					}
				}
			}
			return {};
		}

		InstanceLoadingSource FindInstanceLoadingSource(Ptr<GuiInstanceContext> context, GlobalStringKey namespaceName, const WString& typeName)
		{
			return FindByTag(context, namespaceName, typeName, [](GlobalStringKey fullName)->Nullable<InstanceLoadingSource>
			{
				if (auto loader = GetInstanceLoaderManager()->GetLoader(fullName))
				{
					return { { loader, fullName } };
				}
				return {};
			});
		}

		Ptr<GuiResourceItem> FindInstanceResourceItem(Ptr<GuiInstanceContext> context, GuiConstructorRepr* ctor, Ptr<GuiResourceClassNameRecord> record)
		{
			return FindByTag(context, ctor->typeNamespace, ctor->typeName.ToString(), [=](GlobalStringKey fullName)->Nullable<Ptr<GuiResourceItem>>
			{
				vint index = record->classResources.Keys().IndexOf(fullName.ToString());
				if (index != -1)
				{
					return record->classResources.Values()[index];
				}
				return {};
			});
		}

		InstanceLoadingSource FindInstanceLoadingSource(Ptr<GuiInstanceContext> context, GuiConstructorRepr* ctor)
		{
			return FindInstanceLoadingSource(context, ctor->typeNamespace, ctor->typeName.ToString());
		}

/***********************************************************************
Workflow_PrecompileInstanceContext
***********************************************************************/

		Ptr<workflow::WfModule> Workflow_PrecompileInstanceContext(GuiResourcePrecompileContext& precompileContext, const WString& moduleName, types::ResolvingResult& resolvingResult, GuiResourceError::List& errors)
		{
			auto module = Workflow_CreateModuleWithUsings(resolvingResult.context, moduleName);
			{
				auto block = Workflow_InstallCtorClass(resolvingResult, module);
				Workflow_GenerateCreating(precompileContext, resolvingResult, block, errors);
				Workflow_GenerateBindings(precompileContext, resolvingResult, block, errors);
			}
			return module;
		}

/***********************************************************************
WorkflowEventNamesVisitor
***********************************************************************/

		class WorkflowEventNamesVisitor : public Object, public GuiValueRepr::IVisitor
		{
		public:
			GuiResourcePrecompileContext&		precompileContext;
			types::ResolvingResult&				resolvingResult;
			List<types::PropertyResolving>&		candidatePropertyTypeInfos;
			Ptr<WfClassDeclaration>				instanceClass;
			GuiResourceError::List&				errors;

			IGuiInstanceLoader::TypeInfo		resolvedTypeInfo;

			WorkflowEventNamesVisitor(GuiResourcePrecompileContext& _precompileContext, types::ResolvingResult& _resolvingResult, List<types::PropertyResolving>& _candidatePropertyTypeInfos, Ptr<WfClassDeclaration> _instanceClass, GuiResourceError::List& _errors)
				:precompileContext(_precompileContext)
				, resolvingResult(_resolvingResult)
				, candidatePropertyTypeInfos(_candidatePropertyTypeInfos)
				, instanceClass(_instanceClass)
				, errors(_errors)
			{
			}

			///////////////////////////////////////////////////////////////////////////////////

			Ptr<WfDeclaration> ProcessEvent(
				Ptr<GuiAttSetterRepr::EventValue> handler,
				GlobalStringKey propertyName
				)
			{
				if (auto eventInfo = resolvedTypeInfo.typeInfo->GetTypeDescriptor()->GetEventByName(propertyName.ToString(), true))
				{
					auto decl = Workflow_GenerateEventHandler(precompileContext, eventInfo);
					decl->functionKind = WfFunctionKind::Normal;
					decl->anonymity = WfFunctionAnonymity::Named;
					decl->name.value = handler->value;

					{
						auto att = Ptr(new WfAttribute);
						att->category.value = L"cpp";
						att->name.value = L"Protected";

						decl->attributes.Add(att);
					}
					{
						auto att = Ptr(new WfAttribute);
						att->category.value = L"cpp";
						att->name.value = L"UserImpl";

						decl->attributes.Add(att);
					}

					{
						auto block = Ptr(new WfBlockStatement);
						decl->statement = block;

						auto stringExpr = Ptr(new WfStringExpression);
						stringExpr->value.value = L"Not Implemented: " + handler->value;

						auto raiseStat = Ptr(new WfRaiseExceptionStatement);
						raiseStat->expression = stringExpr;
						block->statements.Add(raiseStat);
					}
					return decl;
				}
				else
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, handler->attPosition,
						L"Precompile: Event \"" +
						propertyName.ToString() +
						L"\" cannot be found in type \"" +
						resolvedTypeInfo.typeName.ToString() +
						L"\"."));
				}
				return nullptr;
			}

			///////////////////////////////////////////////////////////////////////////////////

			void Visit(GuiTextRepr* repr)override
			{
			}

			void Visit(GuiAttSetterRepr* repr)override
			{
				// TODO: (enumerable) foreach on dictionary
				for (auto [setter, index] : indexed(repr->setters.Values()))
				{
					auto loader = GetInstanceLoaderManager()->GetLoader(resolvedTypeInfo.typeName);
					List<types::PropertyResolving> possibleInfos;
					auto prop = repr->setters.Keys()[index];

					WString errorPrefix;
					if (Workflow_GetPropertyTypes(precompileContext, errorPrefix, resolvingResult, loader, resolvedTypeInfo, prop, setter, possibleInfos, errors))
					{
						if (setter->binding == GlobalStringKey::_Set)
						{
							if (possibleInfos[0].info->support == GuiInstancePropertyInfo::SupportSet)
							{
								auto setTarget = dynamic_cast<GuiAttSetterRepr*>(setter->values[0].Obj());

								List<types::PropertyResolving> infos;
								WorkflowEventNamesVisitor visitor(precompileContext, resolvingResult, infos, instanceClass, errors);
								auto typeInfo = possibleInfos[0].info->acceptableTypes[0];
								visitor.resolvedTypeInfo.typeName = GlobalStringKey::Get(typeInfo->GetTypeDescriptor()->GetTypeName());
								visitor.resolvedTypeInfo.typeInfo = typeInfo;
								setTarget->Accept(&visitor);
							}
							else
							{
								errors.Add(GuiResourceError({ resolvingResult.resource }, setter->attPosition, errorPrefix + L" does not support the \"-set\" binding."));
							}
						}
						else
						{
							for (auto value : setter->values)
							{
								WorkflowEventNamesVisitor visitor(precompileContext, resolvingResult, possibleInfos, instanceClass, errors);
								value->Accept(&visitor);
							}
						}
					}
				}

				// TODO: (enumerable) foreach on dictionary
				for (auto [handler, index] : indexed(repr->eventHandlers.Values()))
				{
					if (handler->binding == GlobalStringKey::Empty)
					{
						auto propertyName = repr->eventHandlers.Keys()[index];
						if (auto decl = ProcessEvent(handler, propertyName))
						{
							Workflow_RecordScriptPosition(precompileContext, handler->valuePosition, decl);
							instanceClass->declarations.Add(decl);
						}
					}
				}
			}

			void Visit(GuiConstructorRepr* repr)override
			{
				auto context = resolvingResult.context;

				bool inferType = repr->typeNamespace == GlobalStringKey::Empty&&repr->typeName == GlobalStringKey::_InferType;

				bool noContextToInfer = false;
				if (inferType)
				{
					if (candidatePropertyTypeInfos.Count() == 1)
					{
						auto info = candidatePropertyTypeInfos[0].info;
						if (info->acceptableTypes.Count() == 1)
						{
							auto typeInfo = info->acceptableTypes[0];
							resolvedTypeInfo.typeName = GlobalStringKey::Get(typeInfo->GetTypeDescriptor()->GetTypeName());
							resolvedTypeInfo.typeInfo = typeInfo;
						}
						else if (info->acceptableTypes.Count() == 0)
						{
							noContextToInfer = true;
						}
					}
					else if (candidatePropertyTypeInfos.Count() == 0)
					{
						noContextToInfer = true;
					}
				}
				else
				{
					if (repr == context->instance.Obj())
					{
						auto fullName = GlobalStringKey::Get(context->className);
						if (auto reprType = GetInstanceLoaderManager()->GetTypeInfoForType(fullName))
						{
							resolvedTypeInfo.typeName = fullName;
							resolvedTypeInfo.typeInfo = reprType;
						}
					}
					if (!resolvedTypeInfo.typeInfo)
					{
						auto source = FindInstanceLoadingSource(context, repr);
						resolvedTypeInfo.typeName = source.typeName;
						resolvedTypeInfo.typeInfo = GetInstanceLoaderManager()->GetTypeInfoForType(source.typeName);
					}
				}

				if (resolvedTypeInfo.typeInfo)
				{
					if (repr->setters.Count() == 1 && repr->setters.Keys()[0] == GlobalStringKey::Empty)
					{
						auto setter = repr->setters.Values()[0];
						if (setter->values.Count() == 1)
						{
							if (auto text = setter->values[0].Cast<GuiTextRepr>())
							{
								return;
							}
						}
					}
					Visit((GuiAttSetterRepr*)repr);
				}
				else if (inferType)
				{
					if (noContextToInfer)
					{
						errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition,
							L"Precompile: Unable to resolve type \"_\" without any context."));
					}
					else
					{
						errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition,
							L"Precompile: Unable to resolve type \"_\" since the current property accepts multiple types."));
					}
				}
				else
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition,
						L"Precompile: Failed to find type \"" +
						(repr->typeNamespace == GlobalStringKey::Empty
							? repr->typeName.ToString()
							: repr->typeNamespace.ToString() + L":" + repr->typeName.ToString()
							) +
						L"\"."));
				}
			}
		};

/***********************************************************************
Workflow_GenerateInstanceClass
***********************************************************************/

		class ReplaceDeclImplVisitor
			: public workflow::empty_visitor::DeclarationVisitor
			, public workflow::empty_visitor::VirtualCfeDeclarationVisitor
			, public workflow::empty_visitor::VirtualCseDeclarationVisitor
		{
		public:
			Func<Ptr<WfStatement>()>			statCtor;
			List<Ptr<WfDeclaration>>&			unprocessed;

			ReplaceDeclImplVisitor(Func<Ptr<WfStatement>()> _statCtor, List<Ptr<WfDeclaration>>& _unprocessed)
				:statCtor(_statCtor)
				, unprocessed(_unprocessed)
			{
			}

			void Dispatch(WfVirtualCfeDeclaration* node)override
			{
				node->Accept(static_cast<WfVirtualCfeDeclaration::IVisitor*>(this));
			}

			void Dispatch(WfVirtualCseDeclaration* node)override
			{
				node->Accept(static_cast<WfVirtualCseDeclaration::IVisitor*>(this));
			}

			void Visit(WfFunctionDeclaration* node)override
			{
				node->statement = statCtor();
			}

			void Visit(WfConstructorDeclaration* node)override
			{
				node->statement = statCtor();
			}

			void Visit(WfDestructorDeclaration* node)override
			{
				node->statement = statCtor();
			}

			void Visit(WfClassDeclaration* node)override
			{
				CopyFrom(unprocessed, node->declarations, true);
			}
		};

		Ptr<workflow::WfModule> Workflow_GenerateInstanceClass(GuiResourcePrecompileContext& precompileContext, const WString& moduleName, types::ResolvingResult& resolvingResult, GuiResourceError::List& errors, vint passIndex)
		{
			bool needFunctionBody = false;
			bool needEventHandler = false;
			switch (passIndex)
			{
			case IGuiResourceTypeResolver_Precompile::Instance_CollectInstanceTypes:
				needFunctionBody = false;
				needEventHandler = false;
				break;
			case IGuiResourceTypeResolver_Precompile::Instance_CollectEventHandlers:
				needFunctionBody = false;
				needEventHandler = true;
				break;
			case IGuiResourceTypeResolver_Precompile::Instance_GenerateInstanceClass:
				needFunctionBody = true;
				needEventHandler = true;
				break;
			}
			auto classNameRecord = precompileContext.targetFolder->GetValueByPath(L"ClassNameRecord").Cast<GuiResourceClassNameRecord>();

			Ptr<ITypeInfo> baseType;
			Ptr<GuiResourceItem> baseTypeResourceItem;
			Ptr<GuiInstanceContext> baseTypeContext;
			Ptr<WfType> baseWfType;
			auto context = resolvingResult.context;
			{
				auto source = FindInstanceLoadingSource(context, context->instance.Obj());
				baseType = GetInstanceLoaderManager()->GetTypeInfoForType(source.typeName);
				if (!baseType)
				{
					baseTypeResourceItem = FindInstanceResourceItem(context, context->instance.Obj(), classNameRecord);
				}
				if (!baseType && !baseTypeResourceItem)
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, context->instance->tagPosition,
						L"Precompile: Failed to find type \"" +
						(context->instance->typeNamespace == GlobalStringKey::Empty
							? context->instance->typeName.ToString()
							: context->instance->typeNamespace.ToString() + L":" + context->instance->typeName.ToString()
							) +
						L"\"."));
					return nullptr;
				}
				if (baseTypeResourceItem && needEventHandler)
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, context->instance->tagPosition,
						L"[INTERNAL ERROR] Precompile: Failed to find compiled type in previous passes \"" +
						(context->instance->typeNamespace == GlobalStringKey::Empty
							? context->instance->typeName.ToString()
							: context->instance->typeNamespace.ToString() + L":" + context->instance->typeName.ToString()
							) +
						L"\"."));
					return nullptr;
				}
			}

			if (baseTypeResourceItem)
			{
				baseTypeContext = baseTypeResourceItem->GetContent().Cast<GuiInstanceContext>();

				List<WString> fragments;
				SplitTypeName(baseTypeContext->className, fragments);
				for (auto fragment : fragments)
				{
					if (baseWfType)
					{
						auto type = Ptr(new WfChildType);
						type->parent = baseWfType;
						type->name.value = fragment;
						baseWfType = type;
					}
					else
					{
						auto type = Ptr(new WfTopQualifiedType);
						type->name.value = fragment;
						baseWfType = type;
					}
				}
			}

			///////////////////////////////////////////////////////////////
			// Instance Class
			///////////////////////////////////////////////////////////////

			auto module = Workflow_CreateModuleWithUsings(context, moduleName);
			auto instanceClass = Workflow_InstallClass(context->className, module);
			{
				if (baseWfType)
				{
					instanceClass->baseTypes.Add(baseWfType);
				}
				else
				{
					auto typeInfo = Ptr(new TypeDescriptorTypeInfo(baseType->GetTypeDescriptor(), TypeInfoHint::Normal));
					auto baseType = GetTypeFromTypeInfo(typeInfo.Obj());
					instanceClass->baseTypes.Add(baseType);
				}

				if (context->codeBehind)
				{
					auto value = Ptr(new WfStringExpression);
					value->value.value = instanceClass->name.value;

					auto att = Ptr(new WfAttribute);
					att->category.value = L"cpp";
					att->name.value = L"File";
					att->value = value;

					instanceClass->attributes.Add(att);
				}
			}

			///////////////////////////////////////////////////////////////
			// Inherit from Constructor Class
			///////////////////////////////////////////////////////////////

			if (needFunctionBody)
			{
				auto baseConstructorType = Ptr(new WfReferenceType);
				baseConstructorType->name.value = instanceClass->name.value + L"Constructor";
				instanceClass->baseTypes.Add(baseConstructorType);

				{
					auto value = Ptr(new WfTypeOfTypeExpression);
					value->type = CopyType(baseConstructorType);

					auto att = Ptr(new WfAttribute);
					att->category.value = L"cpp";
					att->name.value = L"Friend";
					att->value = value;

					instanceClass->attributes.Add(att);
				}
			}

			///////////////////////////////////////////////////////////////
			// Helpers
			///////////////////////////////////////////////////////////////

			auto parseClassMembers = [&](const WString& code, const WString& name, List<Ptr<WfDeclaration>>& memberDecls, GuiResourceTextPos position)
			{
				WString wrappedCode = L"module parse_members; class Class {\r\n" + code + L"\r\n}";
				if (auto module = Workflow_ParseModule(precompileContext, { resolvingResult.resource }, wrappedCode, position, errors, { 1,0 }))
				{
					CopyFrom(memberDecls, module->declarations[0].Cast<WfClassDeclaration>()->declarations);
				}
			};

			auto notImplemented = []()
			{
				auto block = Ptr(new WfBlockStatement);

				auto stringExpr = Ptr(new WfStringExpression);
				stringExpr->value.value = L"Not Implemented";

				auto raiseStat = Ptr(new WfRaiseExceptionStatement);
				raiseStat->expression = stringExpr;

				block->statements.Add(raiseStat);
				return block;
			};

			auto getDefaultType = [&](const WString& className)->Tuple<Ptr<ITypeInfo>, WString>
			{
				auto paramTd = GetTypeDescriptor(className);
				if (!paramTd)
				{
					auto source = FindInstanceLoadingSource(resolvingResult.context, {}, className);
					if (auto typeInfo = GetInstanceLoaderManager()->GetTypeInfoForType(source.typeName))
					{
						paramTd = typeInfo->GetTypeDescriptor();
					}
				}

				if (paramTd)
				{
					auto typeInfo = Workflow_GetSuggestedParameterType(precompileContext, paramTd);
					switch (typeInfo->GetDecorator())
					{
					case ITypeInfo::RawPtr: return { typeInfo,className + L"*" };
					case ITypeInfo::SharedPtr: return { typeInfo,className + L"^" };
					default: return { typeInfo,className };
					}
				}
				return { nullptr,className };
			};

			///////////////////////////////////////////////////////////////
			// ref.Members
			///////////////////////////////////////////////////////////////

			if (context->memberScript != L"")
			{
				List<Ptr<WfDeclaration>> memberDecls;
				parseClassMembers(context->memberScript, L"members of instance \"" + context->className + L"\"", memberDecls, context->memberPosition);

				if (!needFunctionBody)
				{
					List<Ptr<WfDeclaration>> unprocessed;
					CopyFrom(unprocessed, memberDecls);

					ReplaceDeclImplVisitor visitor(notImplemented, unprocessed);
					// TODO: (enumerable) foreach
					for (vint i = 0; i < unprocessed.Count(); i++)
					{
						unprocessed[i]->Accept(&visitor);
					}
				}

				CopyFrom(instanceClass->declarations, memberDecls, true);
			}

			///////////////////////////////////////////////////////////////
			// Constructor Declaration
			///////////////////////////////////////////////////////////////

			auto ctor = Ptr(new WfConstructorDeclaration);
			ctor->constructorType = WfConstructorType::RawPtr;
			auto ctorBlock = (!needFunctionBody ? notImplemented() : Ptr(new WfBlockStatement));
			ctor->statement = ctorBlock;

			if (baseWfType)
			{
				auto call = Ptr(new WfBaseConstructorCall);
				ctor->baseConstructorCalls.Add(call);
				call->type = CopyType(instanceClass->baseTypes[0]);
				baseTypeContext = baseTypeResourceItem->GetContent().Cast<GuiInstanceContext>();

				// TODO: (enumerable) foreach
				for (auto parameter : baseTypeContext->parameters)
				{
					auto parameterTypeInfoTuple = getDefaultType(parameter->className.ToString());
					auto expression = Workflow_ParseExpression(
						precompileContext,
						parameter->classPosition.originalLocation,
						L"cast("+parameterTypeInfoTuple.get<1>() + L") (null of object)",
						parameter->classPosition,
						errors,
						{ 0,5 }
						);
					if (!expression)
					{
						auto nullExpr = Ptr(new WfLiteralExpression);
						nullExpr->value = WfLiteralValue::Null;
						expression = nullExpr;
					}
					call->arguments.Add(expression);
				}
			}
			else if (auto group = baseType->GetTypeDescriptor()->GetConstructorGroup())
			{
				auto ctorInfo = group->GetMethod(0);
				vint count = ctorInfo->GetParameterCount();
				if (count > 0)
				{
					if (needFunctionBody)
					{
						if (auto call = resolvingResult.rootLoader->CreateRootInstance(precompileContext, resolvingResult, resolvingResult.rootTypeInfo, resolvingResult.rootCtorArguments, errors))
						{
							ctor->baseConstructorCalls.Add(call);
						}
					}
					else
					{
						auto call = Ptr(new WfBaseConstructorCall);
						ctor->baseConstructorCalls.Add(call);

						call->type = CopyType(instanceClass->baseTypes[0]);
						for (vint i = 0; i < count; i++)
						{
							call->arguments.Add(CreateDefaultValue(ctorInfo->GetParameter(i)->GetType()));
						}
					}
				}
			}

			///////////////////////////////////////////////////////////////
			// ref.LocalizedString (Property)
			///////////////////////////////////////////////////////////////

			for (auto localized : context->localizeds)
			{
				if (auto lsTd = GetTypeDescriptor(localized->className.ToString()))
				{
					ITypeDescriptor* lsiTd = nullptr;
					if (auto group = lsTd->GetMethodGroupByName(L"Get", false))
					{
						vint count = group->GetMethodCount();
						for (vint i = 0; i < count; i++)
						{
							auto method = group->GetMethod(i);
							if (method->GetParameterCount() == 1)
							{
								auto paramTd = method->GetParameter(0)->GetType()->GetTypeDescriptor();
								if (paramTd == description::GetTypeDescriptor<Locale>())
								{
									lsiTd = method->GetReturn()->GetTypeDescriptor();
									break;
								}
							}
						}
					}

					if (lsiTd)
					{
						auto prop = Ptr(new WfAutoPropertyDeclaration);
						instanceClass->declarations.Add(prop);

						prop->functionKind = WfFunctionKind::Normal;
						prop->name.value = localized->name.ToString();
						prop->type = GetTypeFromTypeInfo(Workflow_GetSuggestedParameterType(precompileContext, lsiTd).Obj());
						prop->configConst = WfAPConst::Writable;
						prop->configObserve = WfAPObserve::Observable;

						auto localeNameExpr = Ptr(new WfStringExpression);
						localeNameExpr->value.value = L"en-US";

						auto defaultLocalExpr = Ptr(new WfTypeCastingExpression);
						defaultLocalExpr->strategy = WfTypeCastingStrategy::Strong;
						defaultLocalExpr->type = GetTypeFromTypeInfo(TypeInfoRetriver<Locale>::CreateTypeInfo().Obj());
						defaultLocalExpr->expression = localeNameExpr;

						auto getExpr = Ptr(new WfChildExpression);
						getExpr->parent = GetExpressionFromTypeDescriptor(lsTd);
						getExpr->name.value = L"Get";

						auto callExpr = Ptr(new WfCallExpression);
						callExpr->function = getExpr;
						callExpr->arguments.Add(defaultLocalExpr);
						prop->expression = callExpr;
					}
					else
					{
						errors.Add(GuiResourceError({ resolvingResult.resource }, localized->classPosition,
							L"Precompile: Class \"" +
							localized->className.ToString() +
							L"\" of localized strings \"" +
							localized->name.ToString() +
							L"\" is not a correct localized strings class."));
					}
				}
				else
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, localized->classPosition,
						L"Precompile: Class \"" +
						localized->className.ToString() +
						L"\" of localized strings \"" +
						localized->name.ToString() +
						L"\" cannot be found."));
				}
			}

			///////////////////////////////////////////////////////////////
			// ref.Parameter (Variable, Getter, CtorArgument)
			///////////////////////////////////////////////////////////////

			for (auto parameter : context->parameters)
			{
				auto parameterTypeInfoTuple = getDefaultType(parameter->className.ToString());
				vint errorCount = errors.Count();
				auto type = Workflow_ParseType(precompileContext, { resolvingResult.resource }, parameterTypeInfoTuple.get<1>(), parameter->classPosition, errors);

				if (!needFunctionBody && !parameterTypeInfoTuple.get<0>() && errorCount == errors.Count())
				{
					if (!type || type.Cast<WfReferenceType>() || type.Cast<WfChildType>() || type.Cast<WfTopQualifiedType>())
					{
						type = Workflow_ParseType(precompileContext, { resolvingResult.resource }, parameter->className.ToString() + L"*", parameter->classPosition, errors);
					}
				}
				if (type)
				{
					if (needFunctionBody)
					{
						auto decl = Ptr(new WfVariableDeclaration);
						instanceClass->declarations.Add(decl);

						decl->name.value = L"<parameter>" + parameter->name.ToString();
						decl->type = CopyType(type);
						decl->expression = CreateDefaultValue(parameterTypeInfoTuple.get<0>().Obj());

						auto att = Ptr(new WfAttribute);
						att->category.value = L"cpp";
						att->name.value = L"Private";
						decl->attributes.Add(att);

						Workflow_RecordScriptPosition(precompileContext, parameter->tagPosition, (Ptr<WfDeclaration>)decl);
					}
					{
						auto decl = Ptr(new WfFunctionDeclaration);
						instanceClass->declarations.Add(decl);

						decl->functionKind = WfFunctionKind::Normal;
						decl->anonymity = WfFunctionAnonymity::Named;
						decl->name.value = L"Get" + parameter->name.ToString();
						decl->returnType = CopyType(type);
						if (needFunctionBody)
						{
							auto block = Ptr(new WfBlockStatement);
							decl->statement = block;

							auto ref = Ptr(new WfReferenceExpression);
							ref->name.value = L"<parameter>" + parameter->name.ToString();

							auto returnStat = Ptr(new WfReturnStatement);
							returnStat->expression = ref;
							block->statements.Add(returnStat);
						}
						else
						{
							decl->statement = notImplemented();
						}

						Workflow_RecordScriptPosition(precompileContext, parameter->tagPosition, (Ptr<WfDeclaration>)decl);
					}
					{
						auto decl = Ptr(new WfPropertyDeclaration);
						instanceClass->declarations.Add(decl);

						decl->name.value = parameter->name.ToString();
						decl->type = type;
						decl->getter.value = L"Get" + parameter->name.ToString();

						Workflow_RecordScriptPosition(precompileContext, parameter->tagPosition, (Ptr<WfDeclaration>)decl);
					}
					{
						auto argument = Ptr(new WfFunctionArgument);
						argument->name.value = L"<ctor-parameter>" + parameter->name.ToString();
						argument->type = CopyType(type);
						ctor->arguments.Add(argument);
					}
					if (needFunctionBody)
					{
						auto refLeft = Ptr(new WfReferenceExpression);
						refLeft->name.value = L"<parameter>" + parameter->name.ToString();

						auto refRight = Ptr(new WfReferenceExpression);
						refRight->name.value = L"<ctor-parameter>" + parameter->name.ToString();

						auto assignExpr = Ptr(new WfBinaryExpression);
						assignExpr->op = WfBinaryOperator::Assign;
						assignExpr->first = refLeft;
						assignExpr->second = refRight;

						auto exprStat = Ptr(new WfExpressionStatement);
						exprStat->expression = assignExpr;

						ctorBlock->statements.Add(exprStat);

						Workflow_RecordScriptPosition(precompileContext, parameter->tagPosition, (Ptr<WfStatement>)exprStat);
					}
				}
			}

			///////////////////////////////////////////////////////////////
			// Event Handlers
			///////////////////////////////////////////////////////////////

			if (needEventHandler)
			{
				List<types::PropertyResolving> infos;
				WorkflowEventNamesVisitor visitor(precompileContext, resolvingResult, infos, instanceClass, errors);
				context->instance->Accept(&visitor);
			}

			instanceClass->declarations.Add(ctor);

			///////////////////////////////////////////////////////////////
			// Calling Constructor Class
			///////////////////////////////////////////////////////////////

			if (needFunctionBody)
			{
				{
					auto getRmExpr = Ptr(new WfChildExpression);
					getRmExpr->parent = GetExpressionFromTypeDescriptor(description::GetTypeDescriptor<IGuiResourceManager>());
					getRmExpr->name.value = L"GetResourceManager";

					auto call1Expr = Ptr(new WfCallExpression);
					call1Expr->function = getRmExpr;

					auto getResExpr = Ptr(new WfMemberExpression);
					getResExpr->parent = call1Expr;
					getResExpr->name.value = L"GetResourceFromClassName";

					auto classNameExpr = Ptr(new WfStringExpression);
					classNameExpr->value.value = context->className;

					auto call2Expr = Ptr(new WfCallExpression);
					call2Expr->function = getResExpr;
					call2Expr->arguments.Add(classNameExpr);

					auto varDecl = Ptr(new WfVariableDeclaration);
					varDecl->name.value = L"<resource>";
					varDecl->expression = call2Expr;

					auto varStat = Ptr(new WfVariableStatement);
					varStat->variable = varDecl;

					ctorBlock->statements.Add(varStat);
				}
				{
					auto resRef = Ptr(new WfReferenceExpression);
					resRef->name.value = L"<resource>";

					auto resRef2 = Ptr(new WfReferenceExpression);
					resRef2->name.value = L"<resource>";

					auto wdRef = Ptr(new WfMemberExpression);
					wdRef->parent = resRef2;
					wdRef->name.value = L"WorkingDirectory";

					auto newClassExpr = Ptr(new WfNewClassExpression);
					newClassExpr->type = GetTypeFromTypeInfo(TypeInfoRetriver<Ptr<GuiResourcePathResolver>>::CreateTypeInfo().Obj());
					newClassExpr->arguments.Add(resRef);
					newClassExpr->arguments.Add(wdRef);

					auto varDecl = Ptr(new WfVariableDeclaration);
					varDecl->name.value = L"<resolver>";
					varDecl->expression = newClassExpr;

					auto varStat = Ptr(new WfVariableStatement);
					varStat->variable = varDecl;

					ctorBlock->statements.Add(varStat);
				}
				{
					auto setRef = Ptr(new WfMemberExpression);
					setRef->parent = Ptr(new WfThisExpression);
					setRef->name.value = L"SetResourceResolver";

					auto resolverRef = Ptr(new WfReferenceExpression);
					resolverRef->name.value = L"<resolver>";

					auto callExpr = Ptr(new WfCallExpression);
					callExpr->function = setRef;
					callExpr->arguments.Add(resolverRef);

					auto stat = Ptr(new WfExpressionStatement);
					stat->expression = callExpr;

					ctorBlock->statements.Add(stat);
				}
				{
					auto initRef = Ptr(new WfMemberExpression);
					initRef->parent = Ptr(new WfThisExpression);
					{
						List<WString> fragments;
						SplitTypeName(resolvingResult.context->className, fragments);
						initRef->name.value = L"<" + From(fragments).Aggregate([](const WString& a, const WString& b) {return a + L"-" + b; }) + L">Initialize";
					}

					auto callExpr = Ptr(new WfCallExpression);
					callExpr->function = initRef;
					callExpr->arguments.Add(Ptr(new WfThisExpression));

					auto stat = Ptr(new WfExpressionStatement);
					stat->expression = callExpr;

					ctorBlock->statements.Add(stat);
				}
			}

			///////////////////////////////////////////////////////////////
			// ref.Ctor
			///////////////////////////////////////////////////////////////

			if (context->ctorScript != L"")
			{
				if (auto stat = Workflow_ParseStatement(precompileContext, { resolvingResult.resource }, context->ctorScript, context->ctorPosition, errors))
				{
					if (needFunctionBody)
					{
						if (!stat.Cast<WfBlockStatement>())
						{
							auto block = Ptr(new WfBlockStatement);
							block->statements.Add(stat);
							stat = block;
						}

						auto decl = Ptr(new WfFunctionDeclaration);
						decl->functionKind = WfFunctionKind::Normal;
						decl->anonymity = WfFunctionAnonymity::Named;
						decl->name.value = L"<instance-ctor>";
						decl->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<void>::CreateTypeInfo().Obj());
						decl->statement = stat;
						instanceClass->declarations.Add(decl);

						{
							auto refCtor = Ptr(new WfReferenceExpression);
							refCtor->name.value = L"<instance-ctor>";

							auto callExpr = Ptr(new WfCallExpression);
							callExpr->function = refCtor;

							auto exprStat = Ptr(new WfExpressionStatement);
							exprStat->expression = callExpr;
							ctorBlock->statements.Add(exprStat);
						}
					}
				}
			}

			///////////////////////////////////////////////////////////////
			// Destructor
			///////////////////////////////////////////////////////////////

			auto dtor = Ptr(new WfDestructorDeclaration);
			auto dtorBlock = Ptr(new WfBlockStatement);
			dtor->statement = dtorBlock;

			///////////////////////////////////////////////////////////////
			// ref.Dtor
			///////////////////////////////////////////////////////////////

			if (context->dtorScript != L"")
			{
				if (auto stat = Workflow_ParseStatement(precompileContext, { resolvingResult.resource }, context->dtorScript, context->dtorPosition, errors))
				{
					if (needFunctionBody)
					{
						if (!stat.Cast<WfBlockStatement>())
						{
							auto block = Ptr(new WfBlockStatement);
							block->statements.Add(stat);
							stat = block;
						}

						auto decl = Ptr(new WfFunctionDeclaration);
						decl->functionKind = WfFunctionKind::Normal;
						decl->anonymity = WfFunctionAnonymity::Named;
						decl->name.value = L"<instance-dtor>";
						decl->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<void>::CreateTypeInfo().Obj());
						decl->statement = stat;
						instanceClass->declarations.Add(decl);

						{
							auto refDtor = Ptr(new WfReferenceExpression);
							refDtor->name.value = L"<instance-dtor>";

							auto callExpr = Ptr(new WfCallExpression);
							callExpr->function = refDtor;

							auto exprStat = Ptr(new WfExpressionStatement);
							exprStat->expression = callExpr;
							dtorBlock->statements.Add(exprStat);
						}
					}
				}
			}

			///////////////////////////////////////////////////////////////
			// Clear Binding Subscriptions
			///////////////////////////////////////////////////////////////

			{
				auto ref = Ptr(new WfReferenceExpression);
				ref->name.value = L"FinalizeGeneralInstance";

				Ptr<WfExpression> thisExpr = Ptr(new WfThisExpression);
				ITypeDescriptor* types[] =
				{
					description::GetTypeDescriptor<GuiTemplate>(),
					description::GetTypeDescriptor<GuiCustomControl>(),
					description::GetTypeDescriptor<GuiControlHost>(),
				};

				if (!baseType)
				{
					auto currentContext = context;
					while (!baseType)
					{
						auto item = FindInstanceResourceItem(currentContext, currentContext->instance.Obj(), classNameRecord);
						if (!item) break;

						currentContext = item->GetContent().Cast<GuiInstanceContext>();
						auto source = FindInstanceLoadingSource(currentContext, currentContext->instance.Obj());
						baseType = GetInstanceLoaderManager()->GetTypeInfoForType(source.typeName);
					}
				}

				if (baseType)
				{
					for (auto td : types)
					{
						if (baseType->GetTypeDescriptor()->CanConvertTo(td))
						{
							ref->name.value = L"FinalizeInstanceRecursively";

							Ptr<ITypeInfo> typeInfo = Ptr(new TypeDescriptorTypeInfo(td, TypeInfoHint::Normal));
							typeInfo = Ptr(new RawPtrTypeInfo(typeInfo));

							auto inferExpr = Ptr(new WfInferExpression);
							inferExpr->type = GetTypeFromTypeInfo(typeInfo.Obj());
							inferExpr->expression = thisExpr;
							thisExpr = inferExpr;
							break;
						}
					}
				}

				auto call = Ptr(new WfCallExpression);
				call->function = ref;
				call->arguments.Add(thisExpr);

				auto stat = Ptr(new WfExpressionStatement);
				stat->expression = call;
				dtorBlock->statements.Add(stat);
			}

			instanceClass->declarations.Add(dtor);

			return module;
		}

/***********************************************************************
GuiWorkflowSharedManagerPlugin
***********************************************************************/

#undef ERROR_CODE_PREFIX

		class GuiWorkflowSharedManagerPlugin;
		GuiWorkflowSharedManagerPlugin* sharedManagerPlugin = 0;

		class GuiWorkflowSharedManagerPlugin : public Object, public IGuiPlugin
		{
		protected:
			workflow::Parser				workflowParser;
			Ptr<WfLexicalScopeManager>		workflowManager;

		public:

			GUI_PLUGIN_NAME(GacUI_Compiler_WorkflowSharedManager)
			{
			}

			void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerUnrelatedPlugins)
				{
					sharedManagerPlugin = this;
				}
			}

			void Unload(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerUnrelatedPlugins)
				{
					sharedManagerPlugin = 0;
				}
			}

			WfLexicalScopeManager* GetWorkflowManager(GuiResourceCpuArchitecture targetCpuArchitecture)
			{
				WfCpuArchitecture wfCpuArchitecture = WfCpuArchitecture::AsExecutable;
				switch (targetCpuArchitecture)
				{
				case GuiResourceCpuArchitecture::x86:
					wfCpuArchitecture = WfCpuArchitecture::x86;
					break;
				case GuiResourceCpuArchitecture::x64:
					wfCpuArchitecture = WfCpuArchitecture::x64;
					break;
				default:
					CHECK_FAIL(L"The target CPU architecture is unspecified.");
				}

				if (!workflowManager)
				{
					workflowManager = Ptr(new WfLexicalScopeManager(workflowParser, wfCpuArchitecture));
				}
				else
				{
					CHECK_ERROR(workflowManager->cpuArchitecture == wfCpuArchitecture, L"The target CPU architecture cannot be changed.");
				}
				return workflowManager.Obj();
			}

			Ptr<WfLexicalScopeManager> TransferWorkflowManager()
			{
				auto result = workflowManager;
				workflowManager = nullptr;
				return result;
			}
		};
		GUI_REGISTER_PLUGIN(GuiWorkflowSharedManagerPlugin)

		WfLexicalScopeManager* Workflow_GetSharedManager(GuiResourceCpuArchitecture targetCpuArchitecture)
		{
			return sharedManagerPlugin->GetWorkflowManager(targetCpuArchitecture);
		}

		Ptr<WfLexicalScopeManager> Workflow_TransferSharedManager()
		{
			return sharedManagerPlugin->TransferWorkflowManager();
		}
	}
}


/***********************************************************************
.\WORKFLOWCODEGEN\GUIINSTANCELOADER_WORKFLOWCOLLECTREFERENCES.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace reflection::description;
		using namespace collections;
		using namespace workflow::analyzer;

/***********************************************************************
Workflow_AdjustPropertySearchType
***********************************************************************/

		IGuiInstanceLoader::TypeInfo Workflow_AdjustPropertySearchType(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader::TypeInfo resolvedTypeInfo, GlobalStringKey prop)
		{
			if (resolvedTypeInfo.typeName.ToString() == resolvingResult.context->className)
			{
				if (auto propTd = resolvedTypeInfo.typeInfo->GetTypeDescriptor())
				{
					vint baseCount = propTd->GetBaseTypeDescriptorCount();
					for (vint i = 0; i < baseCount; i++)
					{
						auto baseTd = propTd->GetBaseTypeDescriptor(i);
						if (auto ctorGroup = baseTd->GetConstructorGroup())
						{
							if (ctorGroup->GetMethodCount() == 1)
							{
								auto ctor = ctorGroup->GetMethod(0);
								auto propertyName = prop.ToString();
								auto ctorArgumentName = L"<ctor-parameter>" + propertyName;
								vint paramCount = ctor->GetParameterCount();
								for (vint j = 0; j < paramCount; j++)
								{
									auto parameterInfo = ctor->GetParameter(j);
									if (parameterInfo->GetName() == ctorArgumentName)
									{
										if (baseTd->GetPropertyByName(propertyName, false))
										{
											resolvedTypeInfo.typeInfo = CopyTypeInfo(ctor->GetReturn());
											resolvedTypeInfo.typeName = GlobalStringKey::Get(baseTd->GetTypeName());
											return resolvedTypeInfo;
										}
										break;
									}
								}
							}
						}
					}
				}
			}
			return resolvedTypeInfo;
		}

/***********************************************************************
Workflow_GetPropertyTypes
***********************************************************************/

		bool Workflow_GetPropertyTypes(GuiResourcePrecompileContext& precompileContext, WString& errorPrefix, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, IGuiInstanceLoader::TypeInfo resolvedTypeInfo, GlobalStringKey prop, Ptr<GuiAttSetterRepr::SetterValue> setter, collections::List<types::PropertyResolving>& possibleInfos, GuiResourceError::List& errors)
		{
			resolvedTypeInfo = Workflow_AdjustPropertySearchType(precompileContext, resolvingResult, resolvedTypeInfo, prop);
			bool reportedNotSupported = false;
			IGuiInstanceLoader::PropertyInfo propertyInfo(resolvedTypeInfo, prop);

			errorPrefix = L"Precompile: Property \"" + propertyInfo.propertyName.ToString() + L"\" of type \"" + resolvedTypeInfo.typeName.ToString() + L"\"";
			{
				auto currentLoader = loader;

				while (currentLoader)
				{
					if (auto propertyTypeInfo = currentLoader->GetPropertyType(precompileContext, propertyInfo))
					{
						if (propertyTypeInfo->support == GuiInstancePropertyInfo::NotSupport)
						{
							errors.Add(GuiResourceError({ resolvingResult.resource }, setter->attPosition, errorPrefix + L" is not supported."));
							reportedNotSupported = true;
							break;
						}
						else
						{
							types::PropertyResolving resolving;
							resolving.loader = currentLoader;
							resolving.propertyInfo = propertyInfo;
							resolving.info = propertyTypeInfo;
							possibleInfos.Add(resolving);

							if (setter->binding == GlobalStringKey::_Set)
							{
								break;
							}
						}

						if (propertyTypeInfo->mergability == GuiInstancePropertyInfo::NotMerge)
						{
							break;
						}
					}
					currentLoader = GetInstanceLoaderManager()->GetParentLoader(currentLoader);
				}
			}

			if (possibleInfos.Count() == 0)
			{
				if (!reportedNotSupported)
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, setter->attPosition, errorPrefix + L" does not exist."));
				}
				return false;
			}
			else
			{
				return true;
			}
		}

/***********************************************************************
WorkflowReferenceNamesVisitor
***********************************************************************/

		class WorkflowReferenceNamesVisitor : public Object, public GuiValueRepr::IVisitor
		{
		public:
			GuiResourcePrecompileContext&		precompileContext;
			types::ResolvingResult&				resolvingResult;
			vint&								generatedNameCount;
			GuiResourceError::List&				errors;

			List<types::PropertyResolving>&		candidatePropertyTypeInfos;
			IGuiInstanceLoader::TypeInfo		resolvedTypeInfo;
			vint								selectedPropertyTypeInfo = -1;

			WorkflowReferenceNamesVisitor(GuiResourcePrecompileContext& _precompileContext, types::ResolvingResult& _resolvingResult, List<types::PropertyResolving>& _candidatePropertyTypeInfos, vint& _generatedNameCount, GuiResourceError::List& _errors)
				:precompileContext(_precompileContext)
				, resolvingResult(_resolvingResult)
				, candidatePropertyTypeInfos(_candidatePropertyTypeInfos)
				, generatedNameCount(_generatedNameCount)
				, errors(_errors)
			{
			}

			void Visit(GuiTextRepr* repr)override
			{
				if (selectedPropertyTypeInfo == -1)
				{
					selectedPropertyTypeInfo = 0;
				}
				
				auto candidate = candidatePropertyTypeInfos[selectedPropertyTypeInfo];
				auto propertyInfo = candidate.propertyInfo;
				ITypeDescriptor* td = nullptr;
				{
					auto typeInfo = candidate.info->acceptableTypes[0];
					if (auto deserializer = GetInstanceLoaderManager()->GetInstanceDeserializer(propertyInfo, typeInfo.Obj()))
					{
						td = deserializer->DeserializeAs(propertyInfo, typeInfo.Obj())->GetTypeDescriptor();
					}
					else
					{
						td = typeInfo->GetTypeDescriptor();
					}
				}

				if (auto st = td->GetSerializableType())
				{
					Value value;
					if (st->Deserialize(repr->text, value))
					{
						resolvingResult.propertyResolvings.Add(repr, candidate);
					}
					else
					{
						auto error
							= L"Precompile: Property \""
							+ propertyInfo.propertyName.ToString()
							+ L"\" of type \""
							+ propertyInfo.typeInfo.typeName.ToString()
							+ L"\" does not accept a value of text \""
							+ repr->text
							+ L"\" because it is not in a correct format of the serializable type \""
							+ td->GetTypeName()
							+ L"\".";
						errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition, error));
					}
				}
				else
				{
					switch (td->GetTypeDescriptorFlags())
					{
					case TypeDescriptorFlags::FlagEnum:
					case TypeDescriptorFlags::NormalEnum:
					case TypeDescriptorFlags::Struct:
						{
							if (auto expression = Workflow_ParseTextValue(precompileContext, td, { resolvingResult.resource }, repr->text, repr->tagPosition, errors))
							{
								resolvingResult.propertyResolvings.Add(repr, candidate);
							}
						}
						break;
					default:
						{
							auto error
								= L"Precompile: Property \""
								+ propertyInfo.propertyName.ToString()
								+ L"\" of type \""
								+ propertyInfo.typeInfo.typeName.ToString()
								+ L"\" does not accept a value of text \""
								+ repr->text
								+ L"\" because its type \""
								+ td->GetTypeName()
								+ L"\" is not serializable.";
							errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition, error));
						}
					}
				}
			}

			void Visit(GuiAttSetterRepr* repr)override
			{
				if (candidatePropertyTypeInfos.Count() > 0)
				{
					resolvingResult.propertyResolvings.Add(repr, candidatePropertyTypeInfos[selectedPropertyTypeInfo]);
				}

				bool isReferenceType = (resolvedTypeInfo.typeInfo->GetTypeDescriptor()->GetTypeDescriptorFlags() & TypeDescriptorFlags::ReferenceType) != TypeDescriptorFlags::Undefined;
				if (repr->instanceName == GlobalStringKey::Empty)
				{
					if (isReferenceType)
					{
						auto name = GlobalStringKey::Get(L"<precompile>" + itow(generatedNameCount++));
						repr->instanceName = name;
						resolvingResult.typeInfos.Add(name, resolvedTypeInfo);
					}
				}
				else if (resolvingResult.typeInfos.Keys().Contains(repr->instanceName))
				{
					auto error
						= L"Precompile: Referece name \""
						+ repr->instanceName.ToString()
						+ L"\" conflict with an existing named object.";
					errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition, error));
				}
				else if (!isReferenceType)
				{
					auto error
						= L"Precompile: Reference name \""
						+ repr->instanceName.ToString()
						+ L"\" cannot be added to a non-reference instance of type \""
						+ resolvedTypeInfo.typeName.ToString()
						+ L"\".";
					errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition, error));
				}
				else
				{
					resolvingResult.referenceNames.Add(repr->instanceName);
					resolvingResult.typeInfos.Add(repr->instanceName, resolvedTypeInfo);
				}
			
				auto loader = GetInstanceLoaderManager()->GetLoader(resolvedTypeInfo.typeName);

				// TODO: (enumerable) foreach on dictionary
				for (auto [setter, index] : indexed(repr->setters.Values()))
				{
					List<types::PropertyResolving> possibleInfos;
					auto prop = repr->setters.Keys()[index];

					WString errorPrefix;
					if (Workflow_GetPropertyTypes(precompileContext, errorPrefix, resolvingResult, loader, resolvedTypeInfo, prop, setter, possibleInfos, errors))
					{
						if (setter->binding == GlobalStringKey::Empty)
						{
							for (auto value : setter->values)
							{
								WorkflowReferenceNamesVisitor visitor(precompileContext, resolvingResult, possibleInfos, generatedNameCount, errors);
								value->Accept(&visitor);
							}
						}
						else  if (setter->binding == GlobalStringKey::_Set)
						{
							if (possibleInfos[0].info->support == GuiInstancePropertyInfo::SupportSet)
							{
								auto setTarget = dynamic_cast<GuiAttSetterRepr*>(setter->values[0].Obj());

								WorkflowReferenceNamesVisitor visitor(precompileContext, resolvingResult, possibleInfos, generatedNameCount, errors);
								auto typeInfo = possibleInfos[0].info->acceptableTypes[0];
								visitor.selectedPropertyTypeInfo = 0;
								visitor.resolvedTypeInfo.typeName = GlobalStringKey::Get(typeInfo->GetTypeDescriptor()->GetTypeName());
								visitor.resolvedTypeInfo.typeInfo = typeInfo;
								setTarget->Accept(&visitor);
							}
							else
							{
								errors.Add(GuiResourceError({ resolvingResult.resource }, setter->attPosition, L"[INTERNAL-ERROR] " + errorPrefix + L" does not support the \"-set\" binding."));
							}
						}
						else if (setter->binding != GlobalStringKey::Empty)
						{
							auto binder = GetInstanceLoaderManager()->GetInstanceBinder(setter->binding);
							if (binder)
							{
								if (possibleInfos[0].info->usage == GuiInstancePropertyInfo::ConstructorArgument)
								{
									if (possibleInfos[0].info->bindability == GuiInstancePropertyInfo::NotBindable)
									{
										errors.Add(GuiResourceError({ resolvingResult.resource }, setter->attPosition,
											errorPrefix +
											L" cannot be assigned using binding \"-" +
											setter->binding.ToString() +
											L"\". Because it is a non-bindable constructor argument."));
									}
									else if (!binder->ApplicableToConstructorArgument())
									{
										errors.Add(GuiResourceError({ resolvingResult.resource }, setter->attPosition,
											errorPrefix +
											L" cannot be assigned using binding \"-" +
											setter->binding.ToString() +
											L"\". Because it is a constructor argument, and this binding does not apply to any constructor argument."));
									}
								}
							}
							else
							{
								errors.Add(GuiResourceError({ resolvingResult.resource }, setter->attPosition,
									errorPrefix +
									L" cannot be assigned using an unexisting binding \"-" +
									setter->binding.ToString() +
									L"\"."));
							}

							if (setter->values.Count() == 1 && setter->values[0].Cast<GuiTextRepr>())
							{
								resolvingResult.propertyResolvings.Add(setter->values[0].Obj(), possibleInfos[0]);
							}
							else
							{
								errors.Add(GuiResourceError({ resolvingResult.resource }, setter->attPosition,
									L"Precompile: Binder \"" +
									setter->binding.ToString() +
									L"\" requires the text value of property \"" +
									prop.ToString() +
									L"\"."));
							}
						}
					}
				}

				Group<GlobalStringKey, IGuiInstanceLoader*> properties;
				CopyFrom(
					properties,
					From(repr->setters)
						.SelectMany([=, this](Pair<GlobalStringKey, Ptr<GuiAttSetterRepr::SetterValue>> item)
						{
							return From(item.value->values)
								.Where([=, this](Ptr<GuiValueRepr> value)
								{
									return resolvingResult.propertyResolvings.Keys().Contains(value.Obj());
								})
								.Select([=, this](Ptr<GuiValueRepr> value)
								{
									auto loader = resolvingResult.propertyResolvings[value.Obj()].loader;
									return Pair<GlobalStringKey, IGuiInstanceLoader*>(item.key, loader);
								});
						})
						.Distinct()
					);

				if (resolvingResult.context->instance.Obj() != repr)
				{
					List<GlobalStringKey> requiredProps;
					{
						auto currentLoader = loader;
						while (currentLoader)
						{
							currentLoader->GetRequiredPropertyNames(precompileContext, resolvedTypeInfo, requiredProps);
							currentLoader = GetInstanceLoaderManager()->GetParentLoader(currentLoader);
						}
					}
					for (auto prop : From(requiredProps).Distinct())
					{
						if (!properties.Keys().Contains(prop))
						{
							Ptr<GuiInstancePropertyInfo> info;
							{
								auto currentLoader = loader;
								while (currentLoader && !info)
								{
									info = currentLoader->GetPropertyType(precompileContext, { resolvedTypeInfo, prop });
									currentLoader = GetInstanceLoaderManager()->GetParentLoader(currentLoader);
								}
							}

							errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition,
								L"Precompile: Missing required " +
								WString(info->usage == GuiInstancePropertyInfo::ConstructorArgument ? L"constructor argument" : L"property") +
								L" \"" +
								prop.ToString() +
								L"\" of type \"" +
								resolvedTypeInfo.typeName.ToString() +
								L"\"."));
						}
					}
				}

				while (properties.Count() > 0)
				{
					auto prop = properties.Keys()[0];
					auto loader = properties.GetByIndex(0)[0];
					IGuiInstanceLoader::PropertyInfo propertyInfo(resolvedTypeInfo, prop);

					List<GlobalStringKey> pairProps;
					loader->GetPairedProperties(precompileContext, propertyInfo, pairProps);
					if (pairProps.Count() > 0)
					{
						List<GlobalStringKey> missingProps;
						for (auto key : pairProps)
						{
							if (!properties.Contains(key, loader))
							{
								missingProps.Add(key);
							}
						}

						if (missingProps.Count() > 0)
						{
							WString error
								= L"Precompile: When you assign to property \""
								+ prop.ToString()
								+ L"\" of type \""
								+ resolvedTypeInfo.typeName.ToString()
								+ L"\", the following missing properties are required: ";
							for (auto [key, index] : indexed(missingProps))
							{
								if (index > 0)error += L", ";
								error += L"\"" + key.ToString() + L"\"";
							}
							error += L".";
							errors.Add(GuiResourceError({ resolvingResult.resource }, repr->setters[prop]->attPosition, error));
						}
						
						for (auto key : pairProps)
						{
							properties.Remove(key, loader);
						}
					}
					else
					{
						properties.Remove(prop, loader);
					}
				}

				for (auto handler : repr->eventHandlers.Values())
				{
					if (handler->binding != GlobalStringKey::Empty)
					{
						auto binder = GetInstanceLoaderManager()->GetInstanceEventBinder(handler->binding);
						if (!binder)
						{
							errors.Add(GuiResourceError({ resolvingResult.resource }, handler->attPosition,
								L"The appropriate IGuiInstanceEventBinder of binding \"-" +
								handler->binding.ToString() +
								L"\" cannot be found."));
						}
					}
				}
			}

			void Visit(GuiConstructorRepr* repr)override
			{
				bool found = false;

				bool inferType = repr->typeNamespace == GlobalStringKey::Empty && repr->typeName == GlobalStringKey::_InferType;
				if (inferType)
				{
					if (candidatePropertyTypeInfos.Count() == 1)
					{
						auto info = candidatePropertyTypeInfos[0].info;
						if (info->acceptableTypes.Count() == 1)
						{
							auto typeInfo = info->acceptableTypes[0];
							resolvedTypeInfo.typeName = GlobalStringKey::Get(typeInfo->GetTypeDescriptor()->GetTypeName());
							resolvedTypeInfo.typeInfo = typeInfo;
						}
					}
				}
				else
				{
					if (repr == resolvingResult.context->instance.Obj())
					{
						auto fullName = GlobalStringKey::Get(resolvingResult.context->className);
						if (auto typeInfo = GetInstanceLoaderManager()->GetTypeInfoForType(fullName))
						{
							resolvedTypeInfo.typeName = fullName;
							resolvedTypeInfo.typeInfo = typeInfo;
							found = true;
						}
					}

					if (!found)
					{
						auto source = FindInstanceLoadingSource(resolvingResult.context, repr);
						resolvedTypeInfo.typeName = source.typeName;
						resolvedTypeInfo.typeInfo = GetInstanceLoaderManager()->GetTypeInfoForType(source.typeName);
					}
				}

				if (resolvingResult.context->instance == repr)
				{
					static const wchar_t Prefix[] = L"<ctor-parameter>";
					static const vint PrefixLength = (vint)sizeof(Prefix) / sizeof(*Prefix) - 1;

					auto source = FindInstanceLoadingSource(resolvingResult.context, repr);
					if (auto baseTd = description::GetTypeDescriptor(source.typeName.ToString()))
					{
						if (auto ctorGroup = baseTd->GetConstructorGroup())
						{
							if (ctorGroup->GetMethodCount() == 1)
							{
								auto ctor = ctorGroup->GetMethod(0);
								vint paramCount = ctor->GetParameterCount();
								for (vint i = 0; i < paramCount; i++)
								{
									auto parameterInfo = ctor->GetParameter(i);
									auto ctorArg = parameterInfo->GetName();
									if (ctorArg.Length() > PrefixLength && ctorArg.Left(PrefixLength) == Prefix)
									{
										auto propName = ctorArg.Right(ctorArg.Length() - PrefixLength);
										if (baseTd->GetPropertyByName(propName, false))
										{
											if (!repr->setters.Keys().Contains(GlobalStringKey::Get(propName)))
											{
												errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition,
													L"Precompile: Missing required property \"" +
													propName +
													L"\" of type \"" +
													resolvedTypeInfo.typeName.ToString() +
													L"\" for its base type \"" +
													baseTd->GetTypeName() +
													L"\"."));
											}
										}
									}
								}
							}
						}
					}
				}

				if (resolvedTypeInfo.typeInfo)
				{
					for (vint i = 0; i < candidatePropertyTypeInfos.Count(); i++)
					{
						const auto& typeInfos = candidatePropertyTypeInfos[i].info->acceptableTypes;
						// TODO: (enumerable) foreach
						for (vint j = 0; j < typeInfos.Count(); j++)
						{
							if (resolvedTypeInfo.typeInfo->GetTypeDescriptor()->CanConvertTo(typeInfos[j]->GetTypeDescriptor()))
							{
								selectedPropertyTypeInfo = i;
								goto FINISH_MATCHING;
							}
						}
					}
				FINISH_MATCHING:

					if (selectedPropertyTypeInfo == -1 && candidatePropertyTypeInfos.Count() > 0)
					{
						auto propertyInfo = candidatePropertyTypeInfos[0].propertyInfo;
						auto error 
							= L"Precompile: Property \""
							+ propertyInfo.propertyName.ToString()
							+ L"\" of type \""
							+ propertyInfo.typeInfo.typeName.ToString()
							+ L"\" does not accept a value of type \""
							+ resolvedTypeInfo.typeName.ToString()
							+ L"\" because it only accepts value of the following types: ";
						
						// TODO: (enumerable) foreach
						for (vint i = 0; i < candidatePropertyTypeInfos.Count(); i++)
						{
							const auto& typeInfos = candidatePropertyTypeInfos[i].info->acceptableTypes;
							// TODO: (enumerable) LinqLAggregate
							for (vint j = 0; j < typeInfos.Count(); j++)
							{
								if (i != 0 || j != 0)
								{
									error += L", ";
								}
								error += L"\"" + typeInfos[j]->GetTypeFriendlyName() + L"\"";
							}
						}

						error += L".";
						errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition, error));
					}
					else
					{
						if (repr->setters.Count() == 1 && repr->setters.Keys()[0] == GlobalStringKey::Empty)
						{
							auto setter = repr->setters.Values()[0];
							if (setter->values.Count() == 1)
							{
								if (auto text = setter->values[0].Cast<GuiTextRepr>())
								{
									if (candidatePropertyTypeInfos.Count() == 0)
									{
										errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition,
											L"Precompile: Type \"" +
											resolvedTypeInfo.typeName.ToString() +
											L"\" cannot be used to create an instance."));
									}
									else
									{
										Visit(text.Obj());
										auto index = resolvingResult.propertyResolvings.Keys().IndexOf(text.Obj());
										if (index != -1)
										{
											auto value = resolvingResult.propertyResolvings.Values()[index];
											resolvingResult.propertyResolvings.Remove(text.Obj());
											resolvingResult.propertyResolvings.Add(repr, value);
										}
									}
									return;
								}
							}
						}

						if (resolvingResult.context->instance.Obj() != repr)
						{
							auto loader = GetInstanceLoaderManager()->GetLoader(resolvedTypeInfo.typeName);
							while (loader)
							{
								if (loader->CanCreate(resolvedTypeInfo))
								{
									break;
								}
								loader = GetInstanceLoaderManager()->GetParentLoader(loader);
							}
							if (loader)
							{
								if (repr == resolvingResult.context->instance.Obj())
								{
									List<GlobalStringKey> propertyNames;
									loader->GetPropertyNames(precompileContext, resolvedTypeInfo, propertyNames);
									// TODO: (enumerable) foreach:indexed(alterable(reversed))
									for (vint i = propertyNames.Count() - 1; i >= 0; i--)
									{
										auto info = loader->GetPropertyType(precompileContext, { resolvedTypeInfo, propertyNames[i] });
										if (!info || info->usage == GuiInstancePropertyInfo::Property)
										{
											propertyNames.RemoveAt(i);
										}
									}

									if (propertyNames.Count() == 1)
									{
										if (propertyNames[0] != GlobalStringKey::_ControlTemplate)
										{
											errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition,
												L"Precompile: Type \"" +
												resolvedTypeInfo.typeName.ToString() +
												L"\" cannot be used to create a root instance, because its only constructor parameter is not for a the control template."));
										}
									}
									else if (propertyNames.Count() > 1)
									{
										errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition,
											L"Precompile: Type \"" +
											resolvedTypeInfo.typeName.ToString() +
											L"\" cannot be used to create a root instance, because it has more than one constructor parameters. A root instance type can only have one constructor parameter, which is for the control template."));
									}
								}
							}
							else
							{
								errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition,
									L"Precompile: Type \"" +
									resolvedTypeInfo.typeName.ToString() +
									L"\" cannot be used to create an instance."));
							}
						}
						Visit((GuiAttSetterRepr*)repr);
					}
				}
				else
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition,
						L"[INTERNAL-ERROR] Precompile: Failed to find type \"" +
						(repr->typeNamespace == GlobalStringKey::Empty
							? repr->typeName.ToString()
							: repr->typeNamespace.ToString() + L":" + repr->typeName.ToString()
							) +
						L"\"."));
				}
			}
		};

		Ptr<reflection::description::ITypeInfo> Workflow_GetSuggestedParameterType(GuiResourcePrecompileContext& precompileContext, reflection::description::ITypeDescriptor* typeDescriptor)
		{
			auto elementType = Ptr(new TypeDescriptorTypeInfo(typeDescriptor, TypeInfoHint::Normal));
			if ((typeDescriptor->GetTypeDescriptorFlags() & TypeDescriptorFlags::ReferenceType) != TypeDescriptorFlags::Undefined)
			{
				bool isShared = false;
				bool isRaw = false;
				if (auto ctorGroup = typeDescriptor->GetConstructorGroup())
				{
					vint count = ctorGroup->GetMethodCount();
					for (vint i = 0; i < count; i++)
					{
						auto returnType = ctorGroup->GetMethod(i)->GetReturn();
						switch (returnType->GetDecorator())
						{
						case ITypeInfo::RawPtr: isRaw = true; break;
						case ITypeInfo::SharedPtr: isShared = true; break;
						default:;
						}
					}
				}
				if (!isShared && !isRaw)
				{
					return Ptr(new SharedPtrTypeInfo(elementType));
				}
				else if (isShared)
				{
					return Ptr(new SharedPtrTypeInfo(elementType));
				}
				else
				{
					return Ptr(new RawPtrTypeInfo(elementType));
				}
			}
			else
			{
				return elementType;
			}
		}

		IGuiInstanceLoader::TypeInfo Workflow_CollectReferences(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GuiResourceError::List& errors)
		{
			for (auto parameter : resolvingResult.context->parameters)
			{
				auto type = GetTypeDescriptor(parameter->className.ToString());
				if (!type)
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, parameter->classPosition,
						L"Precompile: Cannot find type \"" +
						parameter->className.ToString() +
						L"\"."));
				}
				else if (resolvingResult.typeInfos.Keys().Contains(parameter->name))
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, parameter->classPosition,
						L"[INTERNAL-ERROR] Precompile: Parameter \"" +
						parameter->name.ToString() +
						L"\" conflict with an existing named object."));
				}
				else
				{
					auto referenceType = Workflow_GetSuggestedParameterType(precompileContext, type);
					resolvingResult.typeInfos.Add(parameter->name, { GlobalStringKey::Get(type->GetTypeName()),referenceType });
				}
			}
			
			List<types::PropertyResolving> infos;
			vint generatedNameCount = 0;
			WorkflowReferenceNamesVisitor visitor(precompileContext, resolvingResult, infos, generatedNameCount, errors);
			resolvingResult.context->instance->Accept(&visitor);
			return visitor.resolvedTypeInfo;
		}
	}
}

/***********************************************************************
.\WORKFLOWCODEGEN\GUIINSTANCELOADER_WORKFLOWGENERATEBINDINGS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace workflow;
		using namespace collections;
		using namespace reflection::description;

/***********************************************************************
WorkflowGenerateBindingVisitor
***********************************************************************/

		class WorkflowGenerateBindingVisitor : public Object, public GuiValueRepr::IVisitor
		{
		public:
			GuiResourcePrecompileContext&		precompileContext;
			types::ResolvingResult&				resolvingResult;
			Ptr<WfBlockStatement>				statements;
			GuiResourceError::List&				errors;
			
			WorkflowGenerateBindingVisitor(GuiResourcePrecompileContext& _precompileContext, types::ResolvingResult& _resolvingResult, Ptr<WfBlockStatement> _statements, GuiResourceError::List& _errors)
				:precompileContext(_precompileContext)
				, resolvingResult(_resolvingResult)
				, errors(_errors)
				, statements(_statements)
			{
			}

			///////////////////////////////////////////////////////////////////////////////////

			Ptr<WfStatement> ProcessPropertyBinding(
				GuiAttSetterRepr* repr,
				IGuiInstanceLoader::TypeInfo reprTypeInfo,
				Ptr<GuiAttSetterRepr::SetterValue> setter,
				GlobalStringKey propertyName
				)
			{
				if (auto binder = GetInstanceLoaderManager()->GetInstanceBinder(setter->binding))
				{
					auto propertyResolving = resolvingResult.propertyResolvings[setter->values[0].Obj()];
					if (propertyResolving.info->usage == GuiInstancePropertyInfo::Property)
					{
						WString expressionCode = setter->values[0].Cast<GuiTextRepr>()->text;
						auto instancePropertyInfo = reprTypeInfo.typeInfo->GetTypeDescriptor()->GetPropertyByName(propertyName.ToString(), true);

						if (instancePropertyInfo || !binder->RequirePropertyExist())
						{
							if (auto statement = binder->GenerateInstallStatement(
								precompileContext,
								resolvingResult,
								repr->instanceName,
								instancePropertyInfo,
								propertyResolving.loader,
								propertyResolving.propertyInfo,
								propertyResolving.info,
								expressionCode,
								setter->values[0]->tagPosition,
								errors))
							{
								return statement;
							}
						}
						else
						{
							errors.Add(GuiResourceError({ resolvingResult.resource }, setter->attPosition,
								L"Precompile: Binder \"" +
								setter->binding.ToString() +
								L"\" requires property \"" +
								propertyName.ToString() +
								L"\" to physically appear in type \"" +
								reprTypeInfo.typeName.ToString() +
								L"\"."));
						}
					}
				}
				else
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, setter->attPosition,
						L"[INTERNAL-ERROR] Precompile: The appropriate IGuiInstanceBinder of binding \"-" +
						setter->binding.ToString() +
						L"\" cannot be found."));
				}
				return nullptr;
			}

			///////////////////////////////////////////////////////////////////////////////////

			Ptr<WfStatement> ProcessEventBinding(
				GuiAttSetterRepr* repr,
				IGuiInstanceLoader::TypeInfo reprTypeInfo,
				Ptr<GuiAttSetterRepr::EventValue> handler,
				GlobalStringKey propertyName
				)
			{
				auto td = reprTypeInfo.typeInfo->GetTypeDescriptor();
				auto eventInfo = td->GetEventByName(propertyName.ToString(), true);

				if (!eventInfo)
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, handler->attPosition,
						L"[INTERNAL-ERROR] Precompile: Event \"" +
						propertyName.ToString() +
						L"\" cannot be found in type \"" +
						reprTypeInfo.typeName.ToString() +
						L"\"."));
				}
				else
				{
					if (handler->binding == GlobalStringKey::Empty)
					{
						return Workflow_InstallEvent(precompileContext, resolvingResult, repr->instanceName, eventInfo, handler->value);
					}
					else
					{
						auto binder = GetInstanceLoaderManager()->GetInstanceEventBinder(handler->binding);
						if (binder)
						{
							return binder->GenerateInstallStatement(precompileContext, resolvingResult, repr->instanceName, eventInfo, handler->value, handler->valuePosition, errors);
						}
						else
						{
							errors.Add(GuiResourceError({ resolvingResult.resource }, handler->attPosition,
								L"[INTERNAL-ERROR] The appropriate IGuiInstanceEventBinder of binding \"-" +
								handler->binding.ToString() +
								L"\" cannot be found."));
						}
					}
				}
				return nullptr;
			}

			///////////////////////////////////////////////////////////////////////////////////

			void Visit(GuiTextRepr* repr)override
			{
			}

			void Visit(GuiAttSetterRepr* repr)override
			{
				IGuiInstanceLoader::TypeInfo reprTypeInfo;
				if (repr->instanceName != GlobalStringKey::Empty)
				{
					reprTypeInfo = resolvingResult.typeInfos[repr->instanceName];
				}
				
				if (reprTypeInfo.typeInfo && (reprTypeInfo.typeInfo->GetTypeDescriptor()->GetTypeDescriptorFlags() & TypeDescriptorFlags::ReferenceType) != TypeDescriptorFlags::Undefined)
				{
					WORKFLOW_ENVIRONMENT_VARIABLE_ADD

					// TODO: (enumerable) foreach on dictionary
					for (auto [setter, index] : indexed(repr->setters.Values()))
					{
						auto propertyName = repr->setters.Keys()[index];
						if (setter->binding != GlobalStringKey::Empty && setter->binding != GlobalStringKey::_Set)
						{
							if (auto statement = ProcessPropertyBinding(repr, reprTypeInfo, setter, propertyName))
							{
								Workflow_RecordScriptPosition(precompileContext, setter->values[0]->tagPosition, statement);
								statements->statements.Add(statement);
							}
						}
						else
						{
							for (auto value : setter->values)
							{
								value->Accept(this);
							}
						}
					}

					// TODO: (enumerable) foreach on dictionary
					for (auto [handler, index] : indexed(repr->eventHandlers.Values()))
					{
						if (reprTypeInfo.typeInfo)
						{
							GlobalStringKey propertyName = repr->eventHandlers.Keys()[index];
							if (auto statement = ProcessEventBinding(repr, reprTypeInfo, handler, propertyName))
							{
								Workflow_RecordScriptPosition(precompileContext, handler->valuePosition, statement);
								statements->statements.Add(statement);
							}
						}
					}

					WORKFLOW_ENVIRONMENT_VARIABLE_REMOVE
				}
			}

			void Visit(GuiConstructorRepr* repr)override
			{
				Visit((GuiAttSetterRepr*)repr);
			}
		};

		void Workflow_GenerateBindings(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, Ptr<WfBlockStatement> statements, GuiResourceError::List& errors)
		{
			WorkflowGenerateBindingVisitor visitor(precompileContext, resolvingResult, statements, errors);
			resolvingResult.context->instance->Accept(&visitor);

			for (auto localized : resolvingResult.context->localizeds)
			{
				auto code = L"bind(" + localized->className.ToString() + L"::Get(presentation::controls::GuiApplication::GetApplication().Locale))";
				if (auto bindExpr = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, code, localized->tagPosition, errors))
				{
					auto instancePropertyInfo = resolvingResult.rootTypeInfo.typeInfo->GetTypeDescriptor()->GetPropertyByName(localized->name.ToString(), true);
					if (auto statement = Workflow_InstallBindProperty(precompileContext, resolvingResult, resolvingResult.context->instance->instanceName, instancePropertyInfo, bindExpr))
					{
						Workflow_RecordScriptPosition(precompileContext, localized->tagPosition, statement);
						statements->statements.Add(statement);
					}
				}
			}
		}
	}
}

/***********************************************************************
.\WORKFLOWCODEGEN\GUIINSTANCELOADER_WORKFLOWGENERATECREATING.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace workflow;
		using namespace workflow::analyzer;
		using namespace reflection::description;

/***********************************************************************
WorkflowGenerateCreatingVisitor
***********************************************************************/

		class WorkflowGenerateCreatingVisitor : public Object, public GuiValueRepr::IVisitor
		{
		public:
			GuiResourcePrecompileContext&		precompileContext;
			types::ResolvingResult&				resolvingResult;
			Ptr<WfBlockStatement>				statements;
			GuiResourceError::List&				errors;
			
			WorkflowGenerateCreatingVisitor(GuiResourcePrecompileContext& _precompileContext, types::ResolvingResult& _resolvingResult, Ptr<WfBlockStatement> _statements, GuiResourceError::List& _errors)
				:precompileContext(_precompileContext)
				, resolvingResult(_resolvingResult)
				, errors(_errors)
				, statements(_statements)
			{
			}

			///////////////////////////////////////////////////////////////////////////////////

			IGuiInstanceLoader::ArgumentInfo GetArgumentInfo(GuiResourceTextPos attPosition, GuiValueRepr* repr)
			{
				IGuiInstanceLoader::PropertyInfo propertyInfo;
				Ptr<ITypeInfo> typeInfo = nullptr;
				bool serializable = false;
				WString textValue;
				GuiResourceTextPos textValuePosition;
				GuiConstructorRepr* ctor = nullptr;

				if (auto text = dynamic_cast<GuiTextRepr*>(repr))
				{
					auto resolving = resolvingResult.propertyResolvings[repr];
					propertyInfo = resolving.propertyInfo;
					typeInfo = resolving.info->acceptableTypes[0];

					serializable = true;
					textValue = text->text;
					textValuePosition = text->tagPosition;
				}
				else if ((ctor = dynamic_cast<GuiConstructorRepr*>(repr)))
				{
					if (ctor->instanceName == GlobalStringKey::Empty)
					{
						auto resolving = resolvingResult.propertyResolvings[repr];
						propertyInfo = resolving.propertyInfo;
						typeInfo = resolving.info->acceptableTypes[0];
					}
					else
					{
						typeInfo = resolvingResult.typeInfos[ctor->instanceName].typeInfo;
					}

					if ((typeInfo->GetTypeDescriptor()->GetTypeDescriptorFlags() & TypeDescriptorFlags::StructType) != TypeDescriptorFlags::Undefined)
					{
						serializable = true;
						auto value = ctor->setters.Values()[0]->values[0].Cast<GuiTextRepr>();
						textValue = value->text;
						textValuePosition = value->tagPosition;
					}
				}

				IGuiInstanceLoader::ArgumentInfo argumentInfo;
				argumentInfo.typeInfo = typeInfo;
				argumentInfo.attPosition = attPosition;

				if (serializable)
				{
					if (auto deserializer = GetInstanceLoaderManager()->GetInstanceDeserializer(propertyInfo, typeInfo.Obj()))
					{
						auto typeInfoAs = deserializer->DeserializeAs(propertyInfo, typeInfo.Obj());
						if (auto expression = Workflow_ParseTextValue(precompileContext, typeInfoAs->GetTypeDescriptor(), { resolvingResult.resource }, textValue, textValuePosition, errors))
						{
							argumentInfo.expression = deserializer->Deserialize(precompileContext, resolvingResult, propertyInfo, typeInfo.Obj(), expression, textValuePosition, errors);
						}
					}
					else
					{
						argumentInfo.expression = Workflow_ParseTextValue(precompileContext, typeInfo->GetTypeDescriptor(), { resolvingResult.resource }, textValue, textValuePosition, errors);
					}
					argumentInfo.valuePosition = textValuePosition;
				}
				else
				{
					repr->Accept(this);

					auto ref = Ptr(new WfReferenceExpression);
					ref->name.value = ctor->instanceName.ToString();
					argumentInfo.expression = ref;
				}

				if (argumentInfo.expression)
				{
					Workflow_RecordScriptPosition(precompileContext, repr->tagPosition, argumentInfo.expression);
				}
				return argumentInfo;
			}

			///////////////////////////////////////////////////////////////////////////////////

			Ptr<WfStatement> ProcessPropertySet(
				IGuiInstanceLoader::PropertyInfo propInfo,
				GuiAttSetterRepr* repr,
				Ptr<GuiAttSetterRepr::SetterValue> setter,
				GuiAttSetterRepr* setTarget
				)
			{
				auto info = resolvingResult.propertyResolvings[setTarget];
				vint errorCount = errors.Count();
				if (auto expr = info.loader->GetParameter(precompileContext, resolvingResult, propInfo, repr->instanceName, setter->attPosition, errors))
				{
					auto refInstance = Ptr(new WfReferenceExpression);
					refInstance->name.value = setTarget->instanceName.ToString();

					auto assign = Ptr(new WfBinaryExpression);
					assign->op = WfBinaryOperator::Assign;
					assign->first = refInstance;
					assign->second = expr;

					auto stat = Ptr(new WfExpressionStatement);
					stat->expression = assign;

					return stat;
				}
				else if (errorCount == errors.Count())
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, setTarget->tagPosition,
						L"[INTERNAL-ERROR] Precompile: Something is wrong when retriving the property \"" +
						propInfo.propertyName.ToString() +
						L"\" from an instance of type \"" +
						propInfo.typeInfo.typeName.ToString() +
						L"\"."));
				}
				return nullptr;
			}

			///////////////////////////////////////////////////////////////////////////////////

			Ptr<WfStatement> ProcessPropertyCollection(
				IGuiInstanceLoader::PropertyInfo propInfo,
				GuiAttSetterRepr* repr,
				Group<GlobalStringKey, IGuiInstanceLoader*>& usedProps,
				Ptr<GuiAttSetterRepr::SetterValue> setter,
				types::PropertyResolving info,
				Ptr<GuiValueRepr> value
				)
			{
				if (!usedProps.Contains(propInfo.propertyName, info.loader))
				{
					usedProps.Add(propInfo.propertyName, info.loader);
				}

				vint errorCount = errors.Count();
				IGuiInstanceLoader::ArgumentMap arguments;
				arguments.Add(propInfo.propertyName, GetArgumentInfo(setter->attPosition, value.Obj()));
				if (auto stat = info.loader->AssignParameters(precompileContext, resolvingResult, propInfo.typeInfo, repr->instanceName, arguments, setter->attPosition, errors))
				{
					return stat;
				}
				else if (errorCount == errors.Count())
				{
					errors.Add(GuiResourceError({ resolvingResult.resource }, value->tagPosition,
						L"[INTERNAL-ERROR] Precompile: Something is wrong when assigning to property " +
						propInfo.propertyName.ToString() +
						L" to an instance of type \"" +
						propInfo.typeInfo.typeName.ToString() +
						L"\"."));
				}
				return nullptr;
			}

			///////////////////////////////////////////////////////////////////////////////////

			Ptr<WfStatement> ProcessPropertyOthers(
				IGuiInstanceLoader::PropertyInfo propInfo,
				GuiAttSetterRepr* repr,
				Group<GlobalStringKey, IGuiInstanceLoader*>& usedProps,
				Ptr<GuiAttSetterRepr::SetterValue> setter,
				types::PropertyResolving info,
				Ptr<GuiValueRepr> value
				)
			{
				List<GlobalStringKey> pairedProps;
				info.loader->GetPairedProperties(precompileContext, propInfo, pairedProps);
				if (pairedProps.Count() == 0)
				{
					pairedProps.Add(propInfo.propertyName);
				}

				vint errorCount = errors.Count();
				IGuiInstanceLoader::ArgumentMap arguments;
				for (auto pairedProp : pairedProps)
				{
					usedProps.Add(pairedProp, info.loader);
					auto pairedSetter = repr->setters[pairedProp];
					for (auto pairedValue : pairedSetter->values)
					{
						auto pairedInfo = resolvingResult.propertyResolvings[pairedValue.Obj()];
						if (pairedInfo.loader == info.loader)
						{
							arguments.Add(pairedProp, GetArgumentInfo(pairedSetter->attPosition, pairedValue.Obj()));
						}
					}
				}

				if (auto stat = info.loader->AssignParameters(precompileContext, resolvingResult, propInfo.typeInfo, repr->instanceName, arguments, setter->attPosition, errors))
				{
					return stat;
				}
				else if (errorCount == errors.Count())
				{
					WString propNames;
					// TODO: (enumerable) Linq:Aggregate
					for (auto [pairedProp, propIndex] : indexed(pairedProps))
					{
						if (propIndex > 0)propNames += L", ";
						propNames += L"\"" + pairedProp.ToString() + L"\"";
					}
					errors.Add(GuiResourceError({ resolvingResult.resource }, value->tagPosition,
						L"[INTERNAL-ERROR] Precompile: Something is wrong when assigning to properties " +
						propNames +
						L" to an instance of type \"" +
						propInfo.typeInfo.typeName.ToString() +
						L"\"."));
				}
				return nullptr;
			}

			///////////////////////////////////////////////////////////////////////////////////

			void Visit(GuiTextRepr* repr)override
			{
			}

			void Visit(GuiAttSetterRepr* repr)override
			{
				auto reprTypeInfo = resolvingResult.typeInfos[repr->instanceName];
				
				if (reprTypeInfo.typeInfo && (reprTypeInfo.typeInfo->GetTypeDescriptor()->GetTypeDescriptorFlags() & TypeDescriptorFlags::ReferenceType) != TypeDescriptorFlags::Undefined)
				{
					WORKFLOW_ENVIRONMENT_VARIABLE_ADD

					Group<GlobalStringKey, IGuiInstanceLoader*> usedProps;
					// TODO: (enumerable) foreach:reversed on dictionary
					for (auto prop : From(repr->setters.Keys()).Reverse())
					{
						auto setter = repr->setters[prop];
						IGuiInstanceLoader::PropertyInfo propInfo(reprTypeInfo, prop);
						if (setter->binding == GlobalStringKey::_Set)
						{
							auto setTarget = dynamic_cast<GuiAttSetterRepr*>(setter->values[0].Obj());
							if (auto statement = ProcessPropertySet(propInfo, repr, setter, setTarget))
							{
								Workflow_RecordScriptPosition(precompileContext, setTarget->tagPosition, statement);
								statements->statements.Add(statement);
							}
							setTarget->Accept(this);
						}
						else if (setter->binding == GlobalStringKey::Empty)
						{
							for (auto value : setter->values)
							{
								auto info = resolvingResult.propertyResolvings[value.Obj()];
								if (info.info->usage == GuiInstancePropertyInfo::Property)
								{
									if (info.info->support == GuiInstancePropertyInfo::SupportCollection)
									{
										if (auto statement = ProcessPropertyCollection(propInfo, repr, usedProps, setter, info, value))
										{
											Workflow_RecordScriptPosition(precompileContext, value->tagPosition, statement);
											statements->statements.Add(statement);
										}
									}
									else if (!usedProps.Contains(prop, info.loader))
									{
										if (auto statement = ProcessPropertyOthers(propInfo, repr, usedProps, setter, info, value))
										{
											Workflow_RecordScriptPosition(precompileContext, value->tagPosition, statement);
											statements->statements.Add(statement);
										}
									}
								}
							}
						}
					}

					WORKFLOW_ENVIRONMENT_VARIABLE_REMOVE
				}
			}

			void FillCtorArguments(GuiConstructorRepr* repr, IGuiInstanceLoader* loader, const IGuiInstanceLoader::TypeInfo& typeInfo, IGuiInstanceLoader::ArgumentMap& arguments)
			{
				WORKFLOW_ENVIRONMENT_VARIABLE_ADD

				// TODO: (enumerable) foreach on dictionary
				for (auto [prop, index] : indexed(repr->setters.Keys()))
				{
					auto setter = repr->setters.Values()[index];
					auto propertyResolving = resolvingResult.propertyResolvings[setter->values[0].Obj()];
					if (propertyResolving.info->usage != GuiInstancePropertyInfo::ConstructorArgument) continue;

					if (setter->binding == GlobalStringKey::Empty)
					{
						for (auto value : setter->values)
						{
							auto argument = GetArgumentInfo(setter->attPosition, value.Obj());
							if (argument.typeInfo && argument.expression)
							{
								arguments.Add(prop, argument);
							}
						}
					}
					else if (auto binder = GetInstanceLoaderManager()->GetInstanceBinder(setter->binding))
					{
						auto value = setter->values[0].Cast<GuiTextRepr>();
						if (auto expression = binder->GenerateConstructorArgument(precompileContext, resolvingResult, loader, propertyResolving.propertyInfo, propertyResolving.info, value->text, value->tagPosition, errors))
						{
							Workflow_RecordScriptPosition(precompileContext, value->tagPosition, expression);

							IGuiInstanceLoader::ArgumentInfo argument;
							argument.expression = expression;
							argument.typeInfo = propertyResolving.info->acceptableTypes[0];
							argument.attPosition = setter->attPosition;
							arguments.Add(prop, argument);
						}
					}
					else if (setter->binding != GlobalStringKey::_Set)
					{
						errors.Add(GuiResourceError({ resolvingResult.resource }, setter->attPosition,
							L"[INTERNAL-ERROR] Precompile: The appropriate IGuiInstanceBinder of binding \"-" +
							setter->binding.ToString() +
							L"\" cannot be found."));
					}
				}

				WORKFLOW_ENVIRONMENT_VARIABLE_REMOVE
			}

			void Visit(GuiConstructorRepr* repr)override
			{
				IGuiInstanceLoader::TypeInfo ctorTypeInfo;
				if (resolvingResult.context->instance.Obj() == repr)
				{
					auto source = FindInstanceLoadingSource(resolvingResult.context, repr);
					ctorTypeInfo.typeName = source.typeName;

					auto typeInfo = GetInstanceLoaderManager()->GetTypeInfoForType(source.typeName);
					ctorTypeInfo.typeInfo = typeInfo;
				}
				else
				{
					ctorTypeInfo = resolvingResult.typeInfos[repr->instanceName];
				}

				auto ctorLoader = GetInstanceLoaderManager()->GetLoader(ctorTypeInfo.typeName);
				while (ctorLoader)
				{
					if (ctorLoader->CanCreate(ctorTypeInfo))
					{
						break;
					}
					ctorLoader = GetInstanceLoaderManager()->GetParentLoader(ctorLoader);
				}

				if (resolvingResult.context->instance.Obj() == repr)
				{
					resolvingResult.rootLoader = ctorLoader;
					FillCtorArguments(repr, ctorLoader, ctorTypeInfo, resolvingResult.rootCtorArguments);

					{
						auto refInstance = Ptr(new WfReferenceExpression);
						refInstance->name.value = repr->instanceName.ToString();

						auto refThis = Ptr(new WfReferenceExpression);
						refThis->name.value = L"<this>";

						auto assign = Ptr(new WfBinaryExpression);
						assign->op = WfBinaryOperator::Assign;
						assign->first = refInstance;
						assign->second = refThis;

						auto stat = Ptr(new WfExpressionStatement);
						stat->expression = assign;

						statements->statements.Add(stat);
					}

					if (resolvingResult.rootCtorArguments.Count() > 0)
					{
						if (auto stat = ctorLoader->InitializeRootInstance(precompileContext, resolvingResult, ctorTypeInfo, repr->instanceName, resolvingResult.rootCtorArguments, errors))
						{
							Workflow_RecordScriptPosition(precompileContext, resolvingResult.context->tagPosition, stat);
							statements->statements.Add(stat);
						}
					}

					for (auto parameter : resolvingResult.context->parameters)
					{
						auto refInstance = Ptr(new WfReferenceExpression);
						refInstance->name.value = parameter->name.ToString();

						auto refThis = Ptr(new WfReferenceExpression);
						refThis->name.value = L"<this>";

						auto refParameter = Ptr(new WfMemberExpression);
						refParameter->parent = refThis;
						refParameter->name.value = parameter->name.ToString();

						auto assign = Ptr(new WfBinaryExpression);
						assign->op = WfBinaryOperator::Assign;
						assign->first = refInstance;
						assign->second = refParameter;

						auto stat = Ptr(new WfExpressionStatement);
						stat->expression = assign;

						statements->statements.Add(stat);
						Workflow_RecordScriptPosition(precompileContext, parameter->tagPosition, (Ptr<WfStatement>)stat);
					}
				}
				else
				{
					IGuiInstanceLoader::ArgumentMap arguments;
					FillCtorArguments(repr, ctorLoader, ctorTypeInfo, arguments);

					vint errorCount = errors.Count();
					if (auto ctorStats = ctorLoader->CreateInstance(precompileContext, resolvingResult, ctorTypeInfo, repr->instanceName, arguments, repr->tagPosition, errors))
					{
						Workflow_RecordScriptPosition(precompileContext, resolvingResult.context->tagPosition, ctorStats);
						statements->statements.Add(ctorStats);
						
						auto instanceName = repr->instanceName.ToString();
						auto generatedNamePrefix = WString::Unmanaged(L"<precompile>");
						if (instanceName.Length() < generatedNamePrefix.Length() || instanceName.Left(generatedNamePrefix.Length()) != generatedNamePrefix)
						{
							auto refName = Ptr(new WfStringExpression);
							refName->value.value = instanceName;

							auto refInstance = Ptr(new WfReferenceExpression);
							refInstance->name.value = instanceName;

							auto refThis = Ptr(new WfReferenceExpression);
							refThis->name.value = L"<this>";

							auto refSetNamedObject = Ptr(new WfMemberExpression);
							refSetNamedObject->parent = refThis;
							refSetNamedObject->name.value = L"SetNamedObject";

							auto refCall = Ptr(new WfCallExpression);
							refCall->function = refSetNamedObject;
							refCall->arguments.Add(refName);
							refCall->arguments.Add(refInstance);

							auto statSetNamedObject = Ptr(new WfExpressionStatement);
							statSetNamedObject->expression = refCall;

							if (auto block = ctorStats.Cast<WfBlockStatement>())
							{
								block->statements.Add(statSetNamedObject);
							}
							else
							{
								statements->statements.Add(statSetNamedObject);
							}
						}
					}
					else if (errorCount == errors.Count())
					{
						errors.Add(GuiResourceError({ resolvingResult.resource }, repr->tagPosition,
							L"[INTERNAL-ERROR] Precompile: Something is wrong when creating an instance of type \"" +
							ctorTypeInfo.typeName.ToString() +
							L"\"."));
					}
				}
				Visit((GuiAttSetterRepr*)repr);
			}
		};

		void Workflow_GenerateCreating(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, Ptr<WfBlockStatement> statements, GuiResourceError::List& errors)
		{
			WorkflowGenerateCreatingVisitor visitor(precompileContext, resolvingResult, statements, errors);
			resolvingResult.context->instance->Accept(&visitor);
		}
	}
}


/***********************************************************************
.\WORKFLOWCODEGEN\GUIINSTANCELOADER_WORKFLOWINSTALLBINDINGS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace workflow;
		using namespace workflow::analyzer;
		using namespace reflection::description;
		using namespace collections;

		using namespace controls;
		using namespace compositions;

/***********************************************************************
Workflow_InstallBindProperty
***********************************************************************/

		Ptr<workflow::WfExpression> Workflow_GetUriProperty(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& protocol, const WString& path, GuiResourceTextPos attPosition, GuiResourceError::List& errors)
		{
			Ptr<WfExpression> resourceExpr;
			{
				auto refResolver = Ptr(new WfReferenceExpression);
				refResolver->name.value = L"<this>";

				auto member = Ptr(new WfMemberExpression);
				member->parent = refResolver;
				member->name.value = L"ResolveResource";

				auto valueProtocol = Ptr(new WfStringExpression);
				valueProtocol->value.value = protocol;

				auto valuePath = Ptr(new WfStringExpression);
				valuePath->value.value = path;

				auto valueBool = Ptr(new WfLiteralExpression);
				valueBool->value = WfLiteralValue::True;

				auto call = Ptr(new WfCallExpression);
				call->function = member;
				call->arguments.Add(valueProtocol);
				call->arguments.Add(valuePath);
				call->arguments.Add(valueBool);

				resourceExpr = call;
			}

			auto td = propInfo->acceptableTypes[0]->GetTypeDescriptor();
			Ptr<ITypeInfo> convertedType;
			{
				if (td->GetSerializableType())
				{
					convertedType = TypeInfoRetriver<Ptr<GuiTextData>>::CreateTypeInfo();
				}
				else if (td == description::GetTypeDescriptor<INativeImage>() || td == description::GetTypeDescriptor<GuiImageData>())
				{
					convertedType = TypeInfoRetriver<Ptr<GuiImageData>>::CreateTypeInfo();
				}
				else
				{
					auto elementType = Ptr(new TypeDescriptorTypeInfo(td, TypeInfoHint::Normal));
					auto pointerType = Ptr(new SharedPtrTypeInfo(elementType));
					convertedType = pointerType;
				}
			}

			Ptr<WfExpression> convertedExpr;
			{
				auto cast = Ptr(new WfTypeCastingExpression);
				cast->expression = resourceExpr;
				cast->type = GetTypeFromTypeInfo(convertedType.Obj());
				cast->strategy = WfTypeCastingStrategy::Strong;

				convertedExpr = cast;
			}

			Ptr<WfExpression> evalExpr;
			{
				if (td->GetSerializableType())
				{
					auto member = Ptr(new WfMemberExpression);
					member->parent = convertedExpr;
					member->name.value = L"Text";

					auto elementType = Ptr(new TypeDescriptorTypeInfo(td, TypeInfoHint::Normal));

					auto cast = Ptr(new WfTypeCastingExpression);
					cast->expression = member;
					cast->type = GetTypeFromTypeInfo(elementType.Obj());
					cast->strategy = WfTypeCastingStrategy::Strong;

					evalExpr = cast;
				}
				else if (td == description::GetTypeDescriptor<INativeImage>())
				{
					auto member = Ptr(new WfMemberExpression);
					member->parent = convertedExpr;
					member->name.value = L"Image";

					evalExpr = member;
				}
				else
				{
					evalExpr = convertedExpr;
				}
			}

			return evalExpr;
		}

		Ptr<workflow::WfStatement> Workflow_InstallUriProperty(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, const WString& protocol, const WString& path, GuiResourceTextPos attPosition, GuiResourceError::List& errors)
		{
			auto evalExpr = Workflow_GetUriProperty(precompileContext, resolvingResult, loader, prop, propInfo, protocol, path, attPosition, errors);

			IGuiInstanceLoader::ArgumentMap arguments;
			{
				IGuiInstanceLoader::ArgumentInfo argumentInfo;
				argumentInfo.typeInfo = propInfo->acceptableTypes[0];
				argumentInfo.expression = evalExpr;
				argumentInfo.attPosition = attPosition;
				arguments.Add(prop.propertyName, argumentInfo);
			}

			return loader->AssignParameters(precompileContext, resolvingResult, prop.typeInfo, variableName, arguments, attPosition, errors);
		}

/***********************************************************************
Workflow_InstallBindProperty
***********************************************************************/

		Ptr<workflow::WfStatement> Workflow_InstallBindProperty(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, Ptr<workflow::WfExpression> bindExpression)
		{
			auto subBlock = Ptr(new WfBlockStatement);
			{
				auto var = Ptr(new WfVariableDeclaration);
				var->name.value = L"<created-subscription>";
				var->expression = bindExpression;

				auto stat = Ptr(new WfVariableStatement);
				stat->variable = var;
				subBlock->statements.Add(stat);
			}
			{
				auto callback = Ptr(new WfFunctionDeclaration);
				callback->functionKind = WfFunctionKind::Normal;
				callback->anonymity = WfFunctionAnonymity::Anonymous;
				callback->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<void>::CreateTypeInfo().Obj());;
				{
					auto arg = Ptr(new WfFunctionArgument);
					arg->name.value = L"<value>";
					arg->type = GetTypeFromTypeInfo(TypeInfoRetriver<Value>::CreateTypeInfo().Obj());
					callback->arguments.Add(arg);
				}
				auto callbackBlock = Ptr(new WfBlockStatement);
				callback->statement = callbackBlock;
				{
					auto refSubscribee = Ptr(new WfReferenceExpression);
					refSubscribee->name.value = variableName.ToString();

					auto member = Ptr(new WfMemberExpression);
					member->parent = refSubscribee;
					member->name.value = propertyInfo->GetName();

					auto var = Ptr(new WfVariableDeclaration);
					var->name.value = L"<old>";
					var->expression = member;

					auto stat = Ptr(new WfVariableStatement);
					stat->variable = var;
					callbackBlock->statements.Add(stat);
				}
				{
					ITypeInfo* propertyType = propertyInfo->GetReturn();
					if (propertyInfo->GetSetter() && propertyInfo->GetSetter()->GetParameterCount() == 1)
					{
						propertyType = propertyInfo->GetSetter()->GetParameter(0)->GetType();
					}

					auto refValue = Ptr(new WfReferenceExpression);
					refValue->name.value = L"<value>";

					auto cast = Ptr(new WfTypeCastingExpression);
					cast->strategy = WfTypeCastingStrategy::Strong;
					cast->expression = refValue;
					cast->type = GetTypeFromTypeInfo(propertyType);

					auto var = Ptr(new WfVariableDeclaration);
					var->name.value = L"<new>";
					var->expression = cast;

					auto stat = Ptr(new WfVariableStatement);
					stat->variable = var;
					callbackBlock->statements.Add(stat);
				}
				{
					auto refOld = Ptr(new WfReferenceExpression);
					refOld->name.value = L"<old>";

					auto refNew = Ptr(new WfReferenceExpression);
					refNew->name.value = L"<new>";

					auto compare = Ptr(new WfBinaryExpression);
					compare->op = WfBinaryOperator::EQ;
					compare->first = refOld;
					compare->second = refNew;

					auto ifStat = Ptr(new WfIfStatement);
					ifStat->expression = compare;
					callbackBlock->statements.Add(ifStat);

					auto ifBlock = Ptr(new WfBlockStatement);
					ifStat->trueBranch = ifBlock;

					auto returnStat = Ptr(new WfReturnStatement);
					ifBlock->statements.Add(returnStat);
				}
				{
					auto refSubscribee = Ptr(new WfReferenceExpression);
					refSubscribee->name.value = variableName.ToString();

					auto member = Ptr(new WfMemberExpression);
					member->parent = refSubscribee;
					member->name.value = propertyInfo->GetName();

					auto refNew = Ptr(new WfReferenceExpression);
					refNew->name.value = L"<new>";

					auto assign = Ptr(new WfBinaryExpression);
					assign->op = WfBinaryOperator::Assign;
					assign->first = member;
					assign->second = refNew;

					auto stat = Ptr(new WfExpressionStatement);
					stat->expression = assign;
					callbackBlock->statements.Add(stat);
				}

				auto funcExpr = Ptr(new WfFunctionExpression);
				funcExpr->function = callback;

				auto refBind = Ptr(new WfReferenceExpression);
				refBind->name.value = L"<created-subscription>";

				auto refEvent = Ptr(new WfMemberExpression);
				refEvent->parent = refBind;
				refEvent->name.value = L"ValueChanged";

				auto attachExpr = Ptr(new WfAttachEventExpression);
				attachExpr->event = refEvent;
				attachExpr->function = funcExpr;

				auto stat = Ptr(new WfExpressionStatement);
				stat->expression = attachExpr;
				subBlock->statements.Add(stat);
			}
			{
				auto refThis = Ptr(new WfReferenceExpression);
				refThis->name.value = L"<this>";

				auto member = Ptr(new WfMemberExpression);
				member->parent = refThis;
				member->name.value = L"AddSubscription";

				auto refBind = Ptr(new WfReferenceExpression);
				refBind->name.value = L"<created-subscription>";

				auto call = Ptr(new WfCallExpression);
				call->function = member;
				call->arguments.Add(refBind);

				auto stat = Ptr(new WfExpressionStatement);
				stat->expression = call;
				subBlock->statements.Add(stat);
			}

			return subBlock;
		}

/***********************************************************************
Workflow_InstallEvalProperty
***********************************************************************/

		Ptr<workflow::WfStatement> Workflow_InstallEvalProperty(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr<GuiInstancePropertyInfo> propInfo, Ptr<workflow::WfExpression> evalExpression, GuiResourceTextPos attPosition, GuiResourceError::List& errors)
		{
			IGuiInstanceLoader::ArgumentMap arguments;
			{
				IGuiInstanceLoader::ArgumentInfo argumentInfo;
				argumentInfo.typeInfo = propInfo->acceptableTypes[0];
				argumentInfo.expression = evalExpression;
				argumentInfo.attPosition = attPosition;
				arguments.Add(prop.propertyName, argumentInfo);
			}

			return loader->AssignParameters(precompileContext, resolvingResult, prop.typeInfo, variableName, arguments, attPosition, errors);
		}

/***********************************************************************
Workflow_InstallEvent
***********************************************************************/

		Ptr<workflow::WfStatement> Workflow_InstallEvent(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IEventInfo* eventInfo, const WString& handlerName)
		{
			vint count = eventInfo->GetHandlerType()->GetElementType()->GetGenericArgumentCount() - 1;

			auto subBlock = Ptr(new WfBlockStatement);
			{
				auto var = Ptr(new WfReferenceExpression);
				var->name.value = variableName.ToString();

				auto member = Ptr(new WfMemberExpression);
				member->parent = var;
				member->name.value = eventInfo->GetName();

				auto refThis = Ptr(new WfReferenceExpression);
				refThis->name.value = L"<this>";

				auto handler = Ptr(new WfMemberExpression);
				handler->parent = refThis;
				handler->name.value = handlerName;

				auto call = Ptr(new WfCallExpression);
				call->function = handler;
				for (vint i = 0; i < count; i++)
				{
					auto argument = Ptr(new WfOrderedNameExpression);
					argument->name.value = L"$" + itow(i + 1);
					call->arguments.Add(argument);
				}

				auto eventHandler = Ptr(new WfOrderedLambdaExpression);
				eventHandler->body = call;

				auto attachEvent = Ptr(new WfAttachEventExpression);
				attachEvent->event = member;
				attachEvent->function = eventHandler;

				auto stat = Ptr(new WfExpressionStatement);
				stat->expression = attachEvent;
				subBlock->statements.Add(stat);
			}

			return subBlock;
		}

/***********************************************************************
Workflow_GenerateEventHandler
***********************************************************************/

		Ptr<workflow::WfFunctionDeclaration> Workflow_GenerateEventHandler(GuiResourcePrecompileContext& precompileContext, description::IEventInfo* eventInfo)
		{
			auto func = Ptr(new WfFunctionDeclaration);
			func->functionKind = WfFunctionKind::Normal;
			func->anonymity = WfFunctionAnonymity::Anonymous;
			func->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<void>::CreateTypeInfo().Obj());

			vint count = eventInfo->GetHandlerType()->GetElementType()->GetGenericArgumentCount() - 1;
			bool standardName = false;
			if (count == 2)
			{
				auto senderType = eventInfo->GetHandlerType()->GetElementType()->GetGenericArgument(1)->GetTypeDescriptor();
				auto argumentType = eventInfo->GetHandlerType()->GetElementType()->GetGenericArgument(2)->GetTypeDescriptor();
				if (senderType == GetTypeDescriptor<GuiGraphicsComposition>())
				{
					auto expectedType = GetTypeDescriptor<GuiEventArgs>();
					List<ITypeDescriptor*> types;
					types.Add(argumentType);
					// TODO: (enumerable) foreach
					for (vint i = 0; i < types.Count(); i++)
					{
						auto type = types[i];
						if (type == expectedType)
						{
							standardName = true;
							break;
						}
						vint baseCount = type->GetBaseTypeDescriptorCount();
						for (vint j = 0; j < baseCount; j++)
						{
							auto baseType = type->GetBaseTypeDescriptor(j);
							if (!types.Contains(baseType))
							{
								types.Add(baseType);
							}
						}
					}
				}
			}

			if (standardName)
			{
				{
					auto arg = Ptr(new WfFunctionArgument);
					arg->name.value = L"sender";
					arg->type = GetTypeFromTypeInfo(eventInfo->GetHandlerType()->GetElementType()->GetGenericArgument(1));
					func->arguments.Add(arg);
				}
				{
					auto arg = Ptr(new WfFunctionArgument);
					arg->name.value = L"arguments";
					arg->type = GetTypeFromTypeInfo(eventInfo->GetHandlerType()->GetElementType()->GetGenericArgument(2));
					func->arguments.Add(arg);
				}
			}
			else
			{
				for (vint i = 0; i < count; i++)
				{
					auto arg = Ptr(new WfFunctionArgument);
					arg->name.value = L"arg" + itow(i + 1);
					arg->type = GetTypeFromTypeInfo(eventInfo->GetHandlerType()->GetElementType()->GetGenericArgument(i + 1));
					func->arguments.Add(arg);
				}
			}

			return func;
		}

/***********************************************************************
Workflow_InstallEvalEvent
***********************************************************************/

		Ptr<workflow::WfStatement> Workflow_InstallEvalEvent(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IEventInfo* eventInfo, Ptr<workflow::WfStatement> evalStatement)
		{
			auto func = Workflow_GenerateEventHandler(precompileContext, eventInfo);

			if (evalStatement.Cast<WfBlockStatement>())
			{
				func->statement = evalStatement;
			}
			else if (evalStatement.Cast<WfCoProviderStatement>())
			{
				func->statement = evalStatement;
			}
			else
			{
				auto funcBlock = Ptr(new WfBlockStatement);
				funcBlock->statements.Add(evalStatement);
				func->statement = funcBlock;
			}

			auto subBlock = Ptr(new WfBlockStatement);

			{
				auto eventHandlerLambda = Ptr(new WfFunctionExpression);
				eventHandlerLambda->function = func;

				auto eventHandler = Ptr(new WfVariableDeclaration);
				eventHandler->name.value = L"<event-handler>";
				eventHandler->expression = eventHandlerLambda;

				auto stat = Ptr(new WfVariableStatement);
				stat->variable = eventHandler;
				subBlock->statements.Add(stat);
			}
			{
				auto var = Ptr(new WfReferenceExpression);
				var->name.value = variableName.ToString();

				auto member = Ptr(new WfMemberExpression);
				member->parent = var;
				member->name.value = eventInfo->GetName();

				auto eventHandler = Ptr(new WfReferenceExpression);
				eventHandler->name.value = L"<event-handler>";

				auto attachEvent = Ptr(new WfAttachEventExpression);
				attachEvent->event = member;
				attachEvent->function = eventHandler;

				auto stat = Ptr(new WfExpressionStatement);
				stat->expression = attachEvent;
				subBlock->statements.Add(stat);
			}

			return subBlock;
		}
	}
}

/***********************************************************************
.\WORKFLOWCODEGEN\GUIINSTANCELOADER_WORKFLOWMODULE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace workflow;
		using namespace workflow::analyzer;
		using namespace reflection::description;
		using namespace collections;

/***********************************************************************
Workflow_CreateModuleWithUsings
***********************************************************************/

		Ptr<workflow::WfModule> Workflow_CreateModuleWithUsings(Ptr<GuiInstanceContext> context, const WString& moduleName)
		{
			auto module = Ptr(new WfModule);
			module->moduleType = WfModuleType::Module;
			module->name.value = moduleName;

			vint index = context->namespaces.Keys().IndexOf(GlobalStringKey());
			if (index != -1)
			{
				auto nss = context->namespaces.Values()[index];
				for (auto ns : nss->namespaces)
				{
					auto path = Ptr(new WfModuleUsingPath);
					module->paths.Add(path);

					auto pathCode = ns->prefix + L"*" + ns->postfix;
					auto reading = pathCode.Buffer();
					while (reading)
					{
						auto delimiter = wcsstr(reading, L"::");
						auto begin = reading;
						auto end = delimiter ? delimiter : begin + wcslen(reading);

						auto wildcard = wcschr(reading, L'*');
						if (wildcard >= end)
						{
							wildcard = nullptr;
						}

						auto item = Ptr(new WfModuleUsingItem);
						path->items.Add(item);
						if (wildcard)
						{
							if (begin < wildcard)
							{
								auto fragment = Ptr(new WfModuleUsingNameFragment);
								item->fragments.Add(fragment);
								fragment->name.value = WString::CopyFrom(begin, vint(wildcard - begin));
							}
							{
								auto fragment = Ptr(new WfModuleUsingWildCardFragment);
								item->fragments.Add(fragment);
							}
							if (wildcard + 1 < end)
							{
								auto fragment = Ptr(new WfModuleUsingNameFragment);
								item->fragments.Add(fragment);
								fragment->name.value = WString::CopyFrom(wildcard + 1, vint(end - wildcard - 1));
							}
						}
						else if (begin < end)
						{
							auto fragment = Ptr(new WfModuleUsingNameFragment);
							item->fragments.Add(fragment);
							fragment->name.value = WString::CopyFrom(begin, vint(end - begin));
						}

						if (delimiter)
						{
							reading = delimiter + 2;
						}
						else
						{
							reading = nullptr;
						}
					}
				}
			}
			return module;
		}

/***********************************************************************
Workflow_InstallWithClass
***********************************************************************/

		WString Workflow_InstallWithClass(const WString& className, Ptr<workflow::WfModule> module, Ptr<workflow::WfDeclaration> decl)
		{
			auto decls = &module->declarations;
			auto reading = className.Buffer();
			while (true)
			{
				auto delimiter = wcsstr(reading, L"::");
				if (delimiter)
				{
					auto ns = Ptr(new WfNamespaceDeclaration);
					ns->name.value = WString::CopyFrom(reading, delimiter - reading);
					decls->Add(ns);
					decls = &ns->declarations;
				}
				else
				{
					decls->Add(decl);
					return reading;
				}
				reading = delimiter + 2;
			}
		}

/***********************************************************************
Workflow_InstallClass
***********************************************************************/

		Ptr<workflow::WfClassDeclaration> Workflow_InstallClass(const WString& className, Ptr<workflow::WfModule> module)
		{
			auto ctorClass = Ptr(new WfClassDeclaration);
			ctorClass->kind = WfClassKind::Class;
			ctorClass->constructorType = WfConstructorType::Undefined;
			ctorClass->name.value = Workflow_InstallWithClass(className, module, ctorClass);
			return ctorClass;
		}

/***********************************************************************
Workflow_InstallCtorClass
***********************************************************************/
		
		Ptr<workflow::WfBlockStatement> Workflow_InstallCtorClass(types::ResolvingResult& resolvingResult, Ptr<workflow::WfModule> module)
		{
			auto ctorClass = Workflow_InstallClass(resolvingResult.context->className + L"Constructor", module);
			Workflow_CreateVariablesForReferenceValues(ctorClass, resolvingResult);

			auto thisParam = Ptr(new WfFunctionArgument);
			thisParam->name.value = L"<this>";
			thisParam->type = GetTypeFromTypeInfo(resolvingResult.rootTypeInfo.typeInfo.Obj());

			auto block = Ptr(new WfBlockStatement);

			auto func = Ptr(new WfFunctionDeclaration);
			func->functionKind = WfFunctionKind::Normal;
			func->anonymity = WfFunctionAnonymity::Named;
			func->arguments.Add(thisParam);
			func->returnType = GetTypeFromTypeInfo(TypeInfoRetriver<void>::CreateTypeInfo().Obj());
			func->statement = block;

			{
				List<WString> fragments;
				SplitTypeName(resolvingResult.context->className, fragments);
				func->name.value = L"<" + From(fragments).Aggregate([](const WString& a, const WString& b) {return a + L"-" + b; }) + L">Initialize";
			}
			{
				auto att = Ptr(new WfAttribute);
				att->category.value = L"cpp";
				att->name.value = L"Protected";
				func->attributes.Add(att);
			}

			ctorClass->declarations.Add(func);
			return block;
		}

/***********************************************************************
Variable
***********************************************************************/

		void Workflow_CreatePointerVariable(Ptr<workflow::WfClassDeclaration> ctorClass, GlobalStringKey name, description::ITypeInfo* typeInfo)
		{
			auto var = Ptr(new WfVariableDeclaration);
			var->name.value = name.ToString();
			var->type = GetTypeFromTypeInfo(typeInfo);

			{
				auto att = Ptr(new WfAttribute);
				att->category.value = L"cpp";
				att->name.value = L"Protected";
				var->attributes.Add(att);
			}

			if (!var->type)
			{
				if (auto ctors = typeInfo->GetTypeDescriptor()->GetConstructorGroup())
				{
					if (ctors->GetMethodCount() > 0)
					{
						auto ctor = ctors->GetMethod(0);
						var->type = GetTypeFromTypeInfo(ctor->GetReturn());
					}
				}
			}

			var->expression = CreateDefaultValue(typeInfo);
			ctorClass->declarations.Add(var);
		}
		
		void Workflow_CreateVariablesForReferenceValues(Ptr<workflow::WfClassDeclaration> ctorClass, types::ResolvingResult& resolvingResult)
		{
			const auto& typeInfos = resolvingResult.typeInfos;
			// TODO: (enumerable) foreach on dictionary
			for (vint i = 0; i < typeInfos.Count(); i++)
			{
				auto key = typeInfos.Keys()[i];
				auto value = typeInfos.Values()[i].typeInfo.Obj();
				Workflow_CreatePointerVariable(ctorClass, key, value);
			}
		}
	}
}

/***********************************************************************
.\WORKFLOWCODEGEN\GUIINSTANCELOADER_WORKFLOWPARSER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace stream;
		using namespace reflection::description;
		using namespace workflow;
		using namespace workflow::analyzer;

/***********************************************************************
Parser
***********************************************************************/

		template<typename T>
		Ptr<T> Workflow_Parse(GuiResourcePrecompileContext& precompileContext, const WString& parserName, GuiResourceLocation location, const WString& code, GuiResourceTextPos position, collections::List<GuiResourceError>& errors, glr::ParsingTextPos availableAfter)
		{
			vint errorCount = errors.Count();
			auto parser = GetParserManager()->GetParser<T>(parserName);
			auto result = parser->Parse(location, code, position, errors);

			if (availableAfter.row != 0 || availableAfter.column != 0)
			{
				// TODO: (enumerable) Linq:Skip
				for (vint i = errorCount; i < errors.Count(); i++)
				{
					auto& error = errors[i];
					if (error.position.row > position.row)
					{
						error.position.row -= availableAfter.row;
					}
					else if (error.position.row == position.row && error.position.column >= position.column)
					{
						error.position.column -= availableAfter.column;
					}
				}
			}

			if (result)
			{
				Workflow_RecordScriptPosition(precompileContext, position, result, availableAfter);
			}
			return result;
		}

		Ptr<workflow::WfType> Workflow_ParseType(GuiResourcePrecompileContext& precompileContext, GuiResourceLocation location, const WString& code, GuiResourceTextPos position, collections::List<GuiResourceError>& errors, glr::ParsingTextPos availableAfter)
		{
			return Workflow_Parse<WfType>(precompileContext, L"WORKFLOW-TYPE", location, code, position, errors, availableAfter);
		}

		Ptr<workflow::WfExpression> Workflow_ParseExpression(GuiResourcePrecompileContext& precompileContext, GuiResourceLocation location, const WString& code, GuiResourceTextPos position, collections::List<GuiResourceError>& errors, glr::ParsingTextPos availableAfter)
		{
			return Workflow_Parse<WfExpression>(precompileContext, L"WORKFLOW-EXPRESSION", location, code, position, errors, availableAfter);
		}

		Ptr<workflow::WfStatement> Workflow_ParseStatement(GuiResourcePrecompileContext& precompileContext, GuiResourceLocation location, const WString& code, GuiResourceTextPos position, collections::List<GuiResourceError>& errors, glr::ParsingTextPos availableAfter)
		{
			return Workflow_Parse<WfStatement>(precompileContext, L"WORKFLOW-STATEMENT", location, code, position, errors, availableAfter);
		}

		Ptr<workflow::WfStatement> Workflow_ParseCoProviderStatement(GuiResourcePrecompileContext& precompileContext, GuiResourceLocation location, const WString& code, GuiResourceTextPos position, collections::List<GuiResourceError>& errors, glr::ParsingTextPos availableAfter)
		{
			return Workflow_Parse<WfStatement>(precompileContext, L"WORKFLOW-COPROVIDER-STATEMENT", location, code, position, errors, availableAfter);
		}

		Ptr<workflow::WfModule> Workflow_ParseModule(GuiResourcePrecompileContext& precompileContext, GuiResourceLocation location, const WString& code, GuiResourceTextPos position, collections::List<GuiResourceError>& errors, glr::ParsingTextPos availableAfter)
		{
			return Workflow_Parse<WfModule>(precompileContext, L"WORKFLOW-MODULE", location, code, position, errors, availableAfter);
		}

/***********************************************************************
Workflow_ModuleToString
***********************************************************************/

		WString Workflow_ModuleToString(Ptr<workflow::WfModule> module)
		{
			return GenerateToStream([&](StreamWriter& writer)
			{
				WfPrint(module, L"", writer);
			});
		}

/***********************************************************************
Converter
***********************************************************************/

		Ptr<workflow::WfExpression> Workflow_ParseTextValue(GuiResourcePrecompileContext& precompileContext, description::ITypeDescriptor* typeDescriptor, GuiResourceLocation location, const WString& textValue, GuiResourceTextPos position, collections::List<GuiResourceError>& errors)
		{
			if (typeDescriptor == description::GetTypeDescriptor<WString>())
			{
				auto valueExpr = Ptr(new WfStringExpression);
				valueExpr->value.value = textValue;
				return valueExpr;
			}
			else if (typeDescriptor == description::GetTypeDescriptor<bool>())
			{
				bool value = false;
				if (!TypedValueSerializerProvider<bool>::Deserialize(textValue, value)) return nullptr;
				auto valueExpr = Ptr(new WfLiteralExpression);
				valueExpr->value = value ? WfLiteralValue::True : WfLiteralValue::False;
				return valueExpr;
			}
#define INTEGER_BRANCH(TYPE) \
			else if (typeDescriptor == description::GetTypeDescriptor<TYPE>()) \
			{ \
				auto valueExpr = Ptr(new WfIntegerExpression); \
				valueExpr->value.value = textValue; \
				auto type = Ptr(new TypeDescriptorTypeInfo(typeDescriptor, TypeInfoHint::Normal)); \
				auto infer = Ptr(new WfInferExpression); \
				infer->type = GetTypeFromTypeInfo(type.Obj()); \
				infer->expression = valueExpr; \
				return infer; \
			}
			INTEGER_BRANCH(vint8_t)
			INTEGER_BRANCH(vint16_t)
			INTEGER_BRANCH(vint32_t)
			INTEGER_BRANCH(vint64_t)
			INTEGER_BRANCH(vuint8_t)
			INTEGER_BRANCH(vuint16_t)
			INTEGER_BRANCH(vuint32_t)
			INTEGER_BRANCH(vuint64_t)
#undef INTEGER_BRANCH
				
#define FLOATING_BRANCH(TYPE) \
			else if (typeDescriptor == description::GetTypeDescriptor<TYPE>()) \
			{ \
				auto valueExpr = Ptr(new WfFloatingExpression); \
				valueExpr->value.value = textValue; \
				auto type = Ptr(new TypeDescriptorTypeInfo(typeDescriptor, TypeInfoHint::Normal)); \
				auto infer = Ptr(new WfInferExpression); \
				infer->type = GetTypeFromTypeInfo(type.Obj()); \
				infer->expression = valueExpr; \
				return infer; \
			}
			FLOATING_BRANCH(float)
			FLOATING_BRANCH(double)
#undef FLOATING_BRANCH

			else if (typeDescriptor->GetSerializableType())
			{
				auto str = Ptr(new WfStringExpression);
				str->value.value = textValue;

				auto type = Ptr(new TypeDescriptorTypeInfo(typeDescriptor, TypeInfoHint::Normal));

				auto cast = Ptr(new WfTypeCastingExpression);
				cast->type = GetTypeFromTypeInfo(type.Obj());
				cast->strategy = WfTypeCastingStrategy::Strong;
				cast->expression = str;

				return cast;
			}
			else if (typeDescriptor->GetTypeDescriptorFlags() == TypeDescriptorFlags::Struct)
			{
				if (auto valueExpr = Workflow_ParseExpression(precompileContext, location, L"{" + textValue + L"}", position, errors, { 0,1 })) // {
				{
					auto type = Ptr(new TypeDescriptorTypeInfo(typeDescriptor, TypeInfoHint::Normal));

					auto infer = Ptr(new WfInferExpression);
					infer->type = GetTypeFromTypeInfo(type.Obj());
					infer->expression = valueExpr;

					return infer;
				}
				return nullptr;
			}
			else if ((typeDescriptor->GetTypeDescriptorFlags() & TypeDescriptorFlags::EnumType) != TypeDescriptorFlags::Undefined)
			{
				if (auto valueExpr = Workflow_ParseExpression(precompileContext, location, L"(" + textValue + L")", position, errors, { 0,1 })) // {
				{
					auto type = Ptr(new TypeDescriptorTypeInfo(typeDescriptor, TypeInfoHint::Normal));

					auto infer = Ptr(new WfInferExpression);
					infer->type = GetTypeFromTypeInfo(type.Obj());
					infer->expression = valueExpr;

					return infer;
				}
				return nullptr;
			}
			else
			{
				CHECK_FAIL(L"vl::presentation::Workflow_ParseTextValue(ITypeDescriptor*, const WString&, GuiResourceError::List&)#This is not a value type.");
			}
		}
	}
}

/***********************************************************************
.\WORKFLOWCODEGEN\GUIINSTANCELOADER_WORKFLOWSCRIPTPOSITION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace workflow;

/***********************************************************************
WorkflowScriptPositionVisitor
***********************************************************************/

		class WorkflowScriptPositionVisitor : public workflow::traverse_visitor::AstVisitor
		{
		public:
			GuiResourcePrecompileContext&					context;
			GuiResourceTextPos								position;
			glr::ParsingTextPos								availableAfter;
			Ptr<types::ScriptPosition>						sp;

			WorkflowScriptPositionVisitor(GuiResourcePrecompileContext& _context, GuiResourceTextPos _position, glr::ParsingTextPos _availableAfter)
				:context(_context)
				, position(_position)
				, availableAfter(_availableAfter)
			{
				vint index = context.additionalProperties.Keys().IndexOf(nullptr);
				if (index == -1)
				{
					context.additionalProperties.Add(nullptr, Ptr(new types::ScriptPosition));
				}
				sp = context.additionalProperties[nullptr].Cast<types::ScriptPosition>();
			}

			void Traverse(glr::ParsingAstBase* node) override
			{
				if (!sp->nodePositions.Keys().Contains(node))
				{
					auto pos = node->codeRange.start;
					if (pos.row == availableAfter.row && pos.column > availableAfter.column)
					{
						pos.column -= availableAfter.column;
					}
					else if (pos.row > availableAfter.row)
					{
						pos.row -= availableAfter.row;
					}

					types::ScriptPositionRecord record;
					record.position = position;
					record.availableAfter = availableAfter;
					if (pos.row < 0 || pos.column < 0)
					{
						record.computedPosition = position;
					}
					else if (pos.row == 0)
					{
						record.computedPosition = { position.originalLocation,{position.row,position.column + pos.column} };
					}
					else
					{
						record.computedPosition = { position.originalLocation,{ position.row + pos.row,pos.column } };
					}

					sp->nodePositions.Add(Ptr(node), record);
				}
			}
		};

/***********************************************************************
WorkflowCompiler_ScriptPosition
***********************************************************************/

		void Workflow_RecordScriptPosition(GuiResourcePrecompileContext& context, GuiResourceTextPos position, Ptr<workflow::WfType> node, glr::ParsingTextPos availableAfter)
		{
			WorkflowScriptPositionVisitor(context, position, availableAfter).InspectInto(node.Obj());
		}

		void Workflow_RecordScriptPosition(GuiResourcePrecompileContext& context, GuiResourceTextPos position, Ptr<workflow::WfExpression> node, glr::ParsingTextPos availableAfter)
		{
			WorkflowScriptPositionVisitor(context, position, availableAfter).InspectInto(node.Obj());
		}

		void Workflow_RecordScriptPosition(GuiResourcePrecompileContext& context, GuiResourceTextPos position, Ptr<workflow::WfStatement> node, glr::ParsingTextPos availableAfter)
		{
			WorkflowScriptPositionVisitor(context, position, availableAfter).InspectInto(node.Obj());
		}

		void Workflow_RecordScriptPosition(GuiResourcePrecompileContext& context, GuiResourceTextPos position, Ptr<workflow::WfDeclaration> node, glr::ParsingTextPos availableAfter)
		{
			WorkflowScriptPositionVisitor(context, position, availableAfter).InspectInto(node.Obj());
		}

		void Workflow_RecordScriptPosition(GuiResourcePrecompileContext& context, GuiResourceTextPos position, Ptr<workflow::WfModule> node, glr::ParsingTextPos availableAfter)
		{
			WorkflowScriptPositionVisitor(context, position, availableAfter).InspectInto(node.Obj());
		}

		Ptr<types::ScriptPosition> Workflow_GetScriptPosition(GuiResourcePrecompileContext& context)
		{
			vint index = context.additionalProperties.Keys().IndexOf(nullptr);
			if (index == -1) return nullptr;
			return context.additionalProperties.Values()[index].Cast<types::ScriptPosition>();
		}

		void Workflow_ClearScriptPosition(GuiResourcePrecompileContext& context)
		{
			context.additionalProperties.Remove(nullptr);
		}
	}
}
