/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "GacUI.h"
#ifndef VCZH_DEBUG_NO_REFLECTION
#include "GacUIReflection.h"
#endif

/***********************************************************************
.\GACUIREFLECTIONHELPER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace helper_types
		{

/***********************************************************************
LocalizedStrings
***********************************************************************/

			WString LocalizedStrings::FirstOrEmpty(const collections::LazyList<WString>& formats)
			{
				return formats.First(WString::Empty);
			}
		}
	}

	namespace reflection
	{
		namespace description
		{
			using namespace glr::xml;
			using namespace stream;
			using namespace collections;
			using namespace presentation;
			using namespace presentation::elements;
			using namespace presentation::compositions;
			using namespace presentation::controls;
			using namespace presentation::theme;
			using namespace presentation::templates;

/***********************************************************************
Serialization (Color)
***********************************************************************/

			Color TypedValueSerializerProvider<Color>::GetDefaultValue()
			{
				return Color();
			}

			bool TypedValueSerializerProvider<Color>::Serialize(const Color& input, WString& output)
			{
				output = input.ToString();
				return true;
			}

			bool TypedValueSerializerProvider<Color>::Deserialize(const WString& input, Color& output)
			{
				output = Color::Parse(input);
				return true;
			}

/***********************************************************************
Serialization (DocumentFontSize)
***********************************************************************/

			DocumentFontSize TypedValueSerializerProvider<DocumentFontSize>::GetDefaultValue()
			{
				return DocumentFontSize();
			}

			bool TypedValueSerializerProvider<DocumentFontSize>::Serialize(const DocumentFontSize& input, WString& output)
			{
				output = input.ToString();
				return true;
			}

			bool TypedValueSerializerProvider<DocumentFontSize>::Deserialize(const WString& input, DocumentFontSize& output)
			{
				output = DocumentFontSize::Parse(input);
				return true;
			}

/***********************************************************************
Serialization (GlobalStringKey)
***********************************************************************/

			GlobalStringKey TypedValueSerializerProvider<GlobalStringKey>::GetDefaultValue()
			{
				return GlobalStringKey();
			}

			bool TypedValueSerializerProvider<GlobalStringKey>::Serialize(const GlobalStringKey& input, WString& output)
			{
				output = input.ToString();
				return true;
			}

			bool TypedValueSerializerProvider<GlobalStringKey>::Deserialize(const WString& input, GlobalStringKey& output)
			{
				output = GlobalStringKey::Get(input);
				return true;
			}

/***********************************************************************
External Functions (Basic)
***********************************************************************/

			Ptr<INativeImage> INativeImage_Constructor(const WString& path)
			{
				return GetCurrentController()->ImageService()->CreateImageFromFile(path);
			}

			INativeCursor* INativeCursor_Constructor1()
			{
				return GetCurrentController()->ResourceService()->GetDefaultSystemCursor();
			}

			INativeCursor* INativeCursor_Constructor2(INativeCursor::SystemCursorType type)
			{
				return GetCurrentController()->ResourceService()->GetSystemCursor(type);
			}

			Ptr<elements::IGuiGraphicsElement> GuiRawElement_Constructor()
			{
				return GetGuiGraphicsResourceManager()->CreateRawElement();
			}

/***********************************************************************
External Functions (Compositions)
***********************************************************************/

			void GuiTableComposition_SetRows(GuiTableComposition* thisObject, vint value)
			{
				vint columns = thisObject->GetColumns();
				if (columns <= 0) columns = 1;
				thisObject->SetRowsAndColumns(value, columns);
			}

			void GuiTableComposition_SetColumns(GuiTableComposition* thisObject, vint value)
			{
				vint row = thisObject->GetRows();
				if (row <= 0) row = 1;
				thisObject->SetRowsAndColumns(row, value);
			}

			void IGuiAltActionHost_CollectAltActions(IGuiAltActionHost* host, List<IGuiAltAction*>& actions)
			{
				Group<WString, IGuiAltAction*> group;
				host->CollectAltActions(group);
				// TODO: (enumerable) Linq:SelectMany
				for (vint i = 0; i < group.Count(); i++)
				{
					CopyFrom(actions, group.GetByIndex(i), true);
				}
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\CONTROLS\GUIAPPLICATION.CPP
***********************************************************************/

extern void GuiMain();

namespace vl
{
	namespace presentation
	{
		extern void GuiInitializeUtilities();
		extern void GuiFinalizeUtilities();

		namespace controls
		{
			using namespace collections;
			using namespace compositions;
			using namespace theme;
			using namespace description;

/***********************************************************************
GuiGlobalShortcutKeyManager
***********************************************************************/

			class GuiGlobalShortcutKeyManager : public GuiShortcutKeyManager
			{
			protected:
				Dictionary<vint, GuiShortcutKeyItem*>		idToItemsMap;
				Dictionary<GuiShortcutKeyItem*, vint>		itemToIdsMap;

				bool IsGlobal() override
				{
					return true;
				}

				bool OnCreatingShortcut(GuiShortcutKeyItem* item) override
				{
					bool ctrl, shift, alt;
					VKEY key;
					item->ReadKeyConfig(ctrl, shift, alt, key);

					vint id = GetCurrentController()->InputService()->RegisterGlobalShortcutKey(ctrl, shift, alt, key);
					if (id < (vint)NativeGlobalShortcutKeyResult::ValidIdBegins) return false;

					idToItemsMap.Add(id, item);
					itemToIdsMap.Add(item, id);
					return true;
				}

				void OnDestroyingShortcut(GuiShortcutKeyItem* item) override
				{
					vint id = itemToIdsMap[item];
					idToItemsMap.Remove(id);
					itemToIdsMap.Remove(item);
					GetCurrentController()->InputService()->UnregisterGlobalShortcutKey(id);
				}

			public:

				GuiShortcutKeyItem* TryGetItemFromId(vint id)
				{
					vint index = idToItemsMap.Keys().IndexOf(id);
					return index == -1 ? nullptr : idToItemsMap.Values()[index];
				}
			};

/***********************************************************************
GuiApplication
***********************************************************************/

			void GuiApplication::InvokeClipboardNotify(compositions::GuiGraphicsComposition* composition, compositions::GuiEventArgs& arguments)
			{
				if(composition->HasEventReceiver())
				{
					composition->GetEventReceiver()->clipboardNotify.Execute(arguments);
				}
				for (auto subComposition : composition->Children())
				{
					InvokeClipboardNotify(subComposition, arguments);
				}
			}

			void GuiApplication::ClipboardUpdated()
			{
				for(vint i=0;i<windows.Count();i++)
				{
					GuiEventArgs arguments=windows[i]->GetNotifyEventArguments();
					windows[i]->ClipboardUpdated.Execute(arguments);
					InvokeClipboardNotify(windows[i]->GetBoundsComposition(), arguments);
				}
			}

			void GuiApplication::GlobalShortcutKeyActivated(vint id)
			{
				auto manager = dynamic_cast<GuiGlobalShortcutKeyManager*>(globalShortcutKeyManager.Obj());
				if (auto item = manager->TryGetItemFromId(id))
				{
					item->Execute();
				}
			}

			void GuiApplication::EnvironmentChanged()
			{
				for (auto window : windows)
				{
					window->NotifyUpdateDisplayFont();
				}
			}

			GuiApplication::GuiApplication()
				:locale(Locale::UserDefault())
			{
				globalShortcutKeyManager = Ptr(new GuiGlobalShortcutKeyManager);
				GetCurrentController()->CallbackService()->InstallListener(this);
			}

			GuiApplication::~GuiApplication()
			{
				if(sharedTooltipControl)
				{
					delete sharedTooltipControl;
					sharedTooltipControl=0;
				}
				GetCurrentController()->CallbackService()->UninstallListener(this);
			}

			INativeWindow* GuiApplication::GetThreadContextNativeWindow(GuiControlHost* controlHost)
			{
				return nullptr;
			}

			void GuiApplication::RegisterWindow(GuiWindow* window)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::GuiApplication::RegisterWindow(GuiWindow*)#"
				CHECK_ERROR(!window->registeredInApplication, ERROR_MESSAGE_PREFIX L"The window has been registered");
				window->registeredInApplication = true;
				windows.Add(window);
				if (auto nativeWindow = window->GetNativeWindow())
				{
					windowMap.Add(nativeWindow, window);
				}
#undef ERROR_MESSAGE_PREFIX
			}

			void GuiApplication::UnregisterWindow(GuiWindow* window)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::GuiApplication::UnregisterWindow(GuiWindow*)#"
				CHECK_ERROR(window->registeredInApplication, ERROR_MESSAGE_PREFIX L"The window has not been registered");
				window->registeredInApplication = false;
				if (auto nativeWindow = window->GetNativeWindow())
				{
					windowMap.Remove(nativeWindow);
				}
				windows.Remove(window);
#undef ERROR_MESSAGE_PREFIX
			}

			void GuiApplication::NotifyNativeWindowChanged(GuiControlHost* controlHost, INativeWindow* previousNativeWindow)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::GuiApplication::NotifyNativeWindowChanged(GuiControlsHost*, INativeWindow*)#"
				if (auto window = dynamic_cast<GuiWindow*>(controlHost))
				{
					if (!window->registeredInApplication) return;
					if (previousNativeWindow)
					{
						CHECK_ERROR(windowMap[previousNativeWindow] == window, ERROR_MESSAGE_PREFIX L"Unpaired arguments.");
						windowMap.Remove(previousNativeWindow);
					}
					if (auto nativeWindow = window->GetNativeWindow())
					{
						windowMap.Add(nativeWindow, window);
					}
				}
#undef ERROR_MESSAGE_PREFIX
			}

			void GuiApplication::RegisterPopupOpened(GuiPopup* popup)
			{
				vint index=openingPopups.IndexOf(popup);
				if(index==-1)
				{
					openingPopups.Add(popup);
				}
			}

			void GuiApplication::RegisterPopupClosed(GuiPopup* popup)
			{
				openingPopups.Remove(popup);
			}

			void GuiApplication::TooltipMouseEnter(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				sharedTooltipHovering=true;
			}

			void GuiApplication::TooltipMouseLeave(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				sharedTooltipHovering=false;
				if(sharedTooltipClosing)
				{
					CloseTooltip();
				}
			}

			Locale GuiApplication::GetLocale()
			{
				return locale;
			}

			void GuiApplication::SetLocale(Locale value)
			{
				if (locale != value)
				{
					locale = value;
					LocaleChanged();
				}
			}

			void GuiApplication::Run(GuiWindow* _mainWindow)
			{
				if (!mainWindow)
				{
					mainWindow = _mainWindow;
					GetCurrentController()->WindowService()->Run(mainWindow->GetNativeWindow());
					mainWindow = nullptr;
				}
			}

			bool GuiApplication::RunOneCycle()
			{
				return GetCurrentController()->WindowService()->RunOneCycle();
			}

			GuiWindow* GuiApplication::GetMainWindow()
			{
				return mainWindow;
			}

			const collections::List<GuiWindow*>& GuiApplication::GetWindows()
			{
				return windows;
			}

			GuiWindow* GuiApplication::GetWindow(NativePoint location)
			{
				INativeWindow* nativeWindow = GetCurrentController()->WindowService()->GetWindow(location);
				if (nativeWindow)
				{
					// TODO: (enumerable) foreach
					for (vint i = 0; i < windows.Count(); i++)
					{
						GuiWindow* window = windows[i];
						if (window->GetNativeWindow() == nativeWindow)
						{
							return window;
						}
					}
				}
				return 0;
			}

			GuiWindow* GuiApplication::GetWindowFromNative(INativeWindow* nativeWindow)
			{
				vint index = windowMap.Keys().IndexOf(nativeWindow);
				return index == -1 ? nullptr : windowMap.Values()[index];
			}

			void GuiApplication::ShowTooltip(GuiControl* owner, GuiControl* tooltip, vint preferredContentWidth, Point location)
			{
				GuiWindow* ownerWindow = dynamic_cast<GuiWindow*>(owner->GetRelatedControlHost());
				if (sharedTooltipOwnerWindow != ownerWindow)
				{
					delete sharedTooltipControl;
					sharedTooltipControl = 0;
				}

				if(!sharedTooltipControl)
				{
					sharedTooltipControl = new GuiTooltip(theme::ThemeName::Tooltip);
					if (ownerWindow)
					{
						if (auto tooltipStyle = ownerWindow->TypedControlTemplateObject(true)->GetTooltipTemplate())
						{
							sharedTooltipControl->SetControlTemplate(tooltipStyle);
						}
					}
					sharedTooltipControl->GetBoundsComposition()->GetEventReceiver()->mouseEnter.AttachMethod(this, &GuiApplication::TooltipMouseEnter);
					sharedTooltipControl->GetBoundsComposition()->GetEventReceiver()->mouseLeave.AttachMethod(this, &GuiApplication::TooltipMouseLeave);
				}

				sharedTooltipHovering=false;
				sharedTooltipClosing=false;
				sharedTooltipOwnerWindow = ownerWindow;
				sharedTooltipOwner=owner;
				sharedTooltipControl->SetTemporaryContentControl(tooltip);
				sharedTooltipControl->SetPreferredContentWidth(preferredContentWidth);
				sharedTooltipControl->SetClientSize(Size(10, 10));
				sharedTooltipControl->ShowPopup(owner, location);
			}

			void GuiApplication::CloseTooltip()
			{
				if(sharedTooltipControl)
				{
					if(sharedTooltipHovering)
					{
						sharedTooltipClosing=true;
					}
					else
					{
						sharedTooltipClosing=false;
						sharedTooltipControl->Close();
					}
				}
			}

			GuiControl* GuiApplication::GetTooltipOwner()
			{
				if(!sharedTooltipControl) return 0;
				if(!sharedTooltipControl->GetTemporaryContentControl()) return 0;
				return sharedTooltipOwner;
			}

			compositions::IGuiShortcutKeyManager* GuiApplication::GetGlobalShortcutKeyManager()
			{
				return globalShortcutKeyManager.Obj();
			}

			WString GuiApplication::GetExecutablePath()
			{
				return GetCurrentController()->GetExecutablePath();
			}

			WString GuiApplication::GetExecutableFolder()
			{
				WString path=GetExecutablePath();
				for(vint i=path.Length()-1;i>=0;i--)
				{
					if(path[i]==L'\\' || path[i]==L'/')
					{
						return path.Sub(0, i+1);
					}
				}
				return L"";
			}

			bool GuiApplication::IsInMainThread(GuiControlHost* controlHost)
			{
				return GetCurrentController()->AsyncService()->IsInMainThread(GetThreadContextNativeWindow(controlHost));
			}

			void GuiApplication::InvokeAsync(const Func<void()>& proc)
			{
				GetCurrentController()->AsyncService()->InvokeAsync(proc);
			}

			void GuiApplication::InvokeInMainThread(GuiControlHost* controlHost, const Func<void()>& proc)
			{
				GetCurrentController()->AsyncService()->InvokeInMainThread(GetThreadContextNativeWindow(controlHost), proc);
			}

			bool GuiApplication::InvokeInMainThreadAndWait(GuiControlHost* controlHost, const Func<void()>& proc, vint milliseconds)
			{
				CHECK_ERROR(!IsInMainThread(controlHost), L"GuiApplication::InvokeInMainThreadAndWait(GuiControlHost*, const Func<void()>&, vint)#This function cannot be called in UI thread.");
				return GetCurrentController()->AsyncService()->InvokeInMainThreadAndWait(GetThreadContextNativeWindow(controlHost), proc, milliseconds);
			}

			Ptr<INativeDelay> GuiApplication::DelayExecute(const Func<void()>& proc, vint milliseconds)
			{
				return GetCurrentController()->AsyncService()->DelayExecute(proc, milliseconds);
			}

			Ptr<INativeDelay> GuiApplication::DelayExecuteInMainThread(const Func<void()>& proc, vint milliseconds)
			{
				return GetCurrentController()->AsyncService()->DelayExecuteInMainThread(proc, milliseconds);
			}

			void GuiApplication::RunGuiTask(GuiControlHost* controlHost, const Func<void()>& proc)
			{
				if (IsInMainThread(controlHost))
				{
					proc();
				}
				else
				{
					InvokeInMainThreadAndWait(controlHost, [&proc]()
					{
						proc();
					});
				}
			}

/***********************************************************************
Helpers
***********************************************************************/

			GuiApplication* application = nullptr;
			bool GACUI_UNITTEST_ONLY_SKIP_THREAD_LOCAL_STORAGE_DISPOSE_STORAGES = false;
			bool GACUI_UNITTEST_ONLY_SKIP_TYPE_AND_PLUGIN_LOAD_UNLOAD = false;

			GuiApplication* GetApplication()
			{
				return application;
			}

/***********************************************************************
GuiApplicationMain
***********************************************************************/

			class UIThreadAsyncScheduler :public Object, public IAsyncScheduler, public Description<UIThreadAsyncScheduler>
			{
			public:
				void Execute(const Func<void()>& callback)override
				{
					GetApplication()->InvokeInMainThread(GetApplication()->GetMainWindow(), callback);
				}

				void ExecuteInBackground(const Func<void()>& callback)override
				{
					GetApplication()->InvokeAsync(callback);
				}

				void DelayExecute(const Func<void()>& callback, vint milliseconds)override
				{
					GetApplication()->DelayExecuteInMainThread(callback, milliseconds);
				}
			};

			class OtherThreadAsyncScheduler :public Object, public IAsyncScheduler, public Description<UIThreadAsyncScheduler>
			{
			public:
				void Execute(const Func<void()>& callback)override
				{
					GetApplication()->InvokeAsync(callback);
				}

				void ExecuteInBackground(const Func<void()>& callback)override
				{
					GetApplication()->InvokeAsync(callback);
				}

				void DelayExecute(const Func<void()>& callback, vint milliseconds)override
				{
					GetApplication()->DelayExecute(callback, milliseconds);
				}
			};

			void GuiApplicationInitialize()
			{
				theme::InitializeTheme();
				if (!GACUI_UNITTEST_ONLY_SKIP_TYPE_AND_PLUGIN_LOAD_UNLOAD)
				{
#ifndef VCZH_DEBUG_NO_REFLECTION
					GetGlobalTypeManager()->Load();
#endif
					GetPluginManager()->Load(true, true);
				}
				else
				{
					GetPluginManager()->Load(false, true);
				}

				GetCurrentController()->InputService()->StartTimer();
				IAsyncScheduler::RegisterSchedulerForCurrentThread(Ptr(new UIThreadAsyncScheduler));
				IAsyncScheduler::RegisterDefaultScheduler(Ptr(new OtherThreadAsyncScheduler));
				GuiInitializeUtilities();
				{
					GuiApplication app;
					application = &app;
					GuiMain();
				}
				application = nullptr;
				GuiFinalizeUtilities();
				IAsyncScheduler::UnregisterDefaultScheduler();
				IAsyncScheduler::UnregisterSchedulerForCurrentThread();
				GetCurrentController()->InputService()->StopTimer();
				theme::FinalizeTheme();
				FinalizeGlobalStorage();

				if (!GACUI_UNITTEST_ONLY_SKIP_TYPE_AND_PLUGIN_LOAD_UNLOAD)
				{
					GetPluginManager()->Unload(true, true);
					DestroyPluginManager();
#ifndef VCZH_DEBUG_NO_REFLECTION
					ResetGlobalTypeManager();
#endif
				}
				else
				{
					GetPluginManager()->Unload(false, true);
				}

				if (!GACUI_UNITTEST_ONLY_SKIP_THREAD_LOCAL_STORAGE_DISPOSE_STORAGES)
				{
					ThreadLocalStorage::DisposeStorages();
				}
			}

			void GuiRawInitialize()
			{
				if (!GACUI_UNITTEST_ONLY_SKIP_TYPE_AND_PLUGIN_LOAD_UNLOAD)
				{
#ifndef VCZH_DEBUG_NO_REFLECTION
					GetGlobalTypeManager()->Load();
#endif
					GetPluginManager()->Load(true, true);
				}
				else
				{
					GetPluginManager()->Load(false, true);
				}

				GetCurrentController()->InputService()->StartTimer();
				IAsyncScheduler::RegisterSchedulerForCurrentThread(Ptr(new UIThreadAsyncScheduler));
				IAsyncScheduler::RegisterDefaultScheduler(Ptr(new OtherThreadAsyncScheduler));
				GuiMain();
				IAsyncScheduler::UnregisterDefaultScheduler();
				IAsyncScheduler::UnregisterSchedulerForCurrentThread();
				GetCurrentController()->InputService()->StopTimer();
				FinalizeGlobalStorage();

				if (!GACUI_UNITTEST_ONLY_SKIP_TYPE_AND_PLUGIN_LOAD_UNLOAD)
				{
					GetPluginManager()->Unload(true, true);
					DestroyPluginManager();
#ifndef VCZH_DEBUG_NO_REFLECTION
					ResetGlobalTypeManager();
#endif
				}
				else
				{
					GetPluginManager()->Unload(false, true);
				}

				if (!GACUI_UNITTEST_ONLY_SKIP_THREAD_LOCAL_STORAGE_DISPOSE_STORAGES)
				{
					ThreadLocalStorage::DisposeStorages();
				}
			}
		}
	}
}

void GuiRawMain()
{
	vl::presentation::controls::GuiRawInitialize();
}

void GuiApplicationMain()
{
	vl::presentation::controls::GuiApplicationInitialize();
}

/***********************************************************************
.\APPLICATION\CONTROLS\GUIBASICCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace elements;
			using namespace compositions;
			using namespace collections;
			using namespace reflection::description;

/***********************************************************************
GuiDisposedFlag
***********************************************************************/

			void GuiDisposedFlag::SetDisposed()
			{
				disposed = true;
			}

			GuiDisposedFlag::GuiDisposedFlag(GuiControl* _owner)
				:owner(_owner)
			{
			}

			GuiDisposedFlag::~GuiDisposedFlag()
			{
			}

			bool GuiDisposedFlag::IsDisposed()
			{
				return disposed;
			}

/***********************************************************************
GuiControl
***********************************************************************/

			Ptr<GuiDisposedFlag> GuiControl::GetDisposedFlag()
			{
				if (!disposedFlag)
				{
					disposedFlag = Ptr(new GuiDisposedFlag(this));
				}
				return disposedFlag;
			}

			void GuiControl::BeforeControlTemplateUninstalled()
			{
			}

			void GuiControl::AfterControlTemplateInstalled(bool initialize)
			{
				controlTemplateObject->SetText(text);
				controlTemplateObject->SetFont(displayFont);
				controlTemplateObject->SetContext(context);
				controlTemplateObject->SetVisuallyEnabled(isVisuallyEnabled);
				controlTemplateObject->SetFocusableComposition(focusableComposition);
				controlTemplateObject->SetFocused(isFocused);
			}

			void GuiControl::CheckAndStoreControlTemplate(templates::GuiControlTemplate* value)
			{
				controlTemplateObject = value;
			}

			void GuiControl::EnsureControlTemplateExists()
			{
				if (!controlTemplateObject)
				{
					RebuildControlTemplate();
				}
			}

			void GuiControl::RebuildControlTemplate()
			{
				bool initialize = controlTemplateObject == nullptr;
				if (controlTemplateObject)
				{
					BeforeControlTemplateUninstalled();
					containerComposition->GetParent()->RemoveChild(containerComposition);
					boundsComposition->AddChild(containerComposition);
					SafeDeleteComposition(controlTemplateObject);
					controlTemplateObject = nullptr;
				}

				if (controlTemplate)
				{
					CheckAndStoreControlTemplate(controlTemplate({}));
				}
				else
				{
					CheckAndStoreControlTemplate(theme::GetCurrentTheme()->CreateStyle(controlThemeName)({}));
				}

				if (controlTemplateObject)
				{
					controlTemplateObject->SetAlignmentToParent(Margin(0, 0, 0, 0));

					containerComposition->GetParent()->RemoveChild(containerComposition);
					boundsComposition->AddChild(controlTemplateObject);
					controlTemplateObject->GetContainerComposition()->AddChild(containerComposition);
					AfterControlTemplateInstalled(initialize);
				}
			}

			void GuiControl::FixingMissingControlTemplateCallback(templates::GuiControlTemplate* value)
			{
			}

			void GuiControl::CallFixingMissingControlTemplateCallback()
			{
				if (controlTemplateObject)
				{
					FixingMissingControlTemplateCallback(controlTemplateObject);
				}
			}

			void GuiControl::OnChildInserted(GuiControl* control)
			{
				GuiControl* oldParent=control->parent;
				children.Add(control);
				control->parent=this;
				control->OnParentChanged(oldParent, control->parent);
				control->UpdateVisuallyEnabled();
				control->UpdateDisplayFont();

				if (auto host = boundsComposition->GetRelatedGraphicsHost())
				{
					host->InvalidateTabOrderCache();
				}
			}

			void GuiControl::OnChildRemoved(GuiControl* control)
			{
				GuiControl* oldParent=control->parent;
				control->parent=0;
				children.Remove(control);
				control->OnParentChanged(oldParent, control->parent);

				if (auto host = boundsComposition->GetRelatedGraphicsHost())
				{
					host->InvalidateTabOrderCache();
				}
			}

			void GuiControl::OnParentChanged(GuiControl* oldParent, GuiControl* newParent)
			{
				OnParentLineChanged();
			}

			void GuiControl::OnParentLineChanged()
			{
				{
					GuiControlSignalEventArgs arguments(boundsComposition);
					arguments.controlSignal = ControlSignal::ParentLineChanged;
					ControlSignalTrigerred.Execute(arguments);
				}
				// TODO: (enumerable) foreach
				for(vint i=0;i<children.Count();i++)
				{
					children[i]->OnParentLineChanged();
				}
			}

			void GuiControl::OnServiceAdded()
			{
				{
					GuiControlSignalEventArgs arguments(boundsComposition);
					arguments.controlSignal = ControlSignal::ServiceAdded;
					ControlSignalTrigerred.Execute(arguments);
				}
				// TODO: (enumerable) foreach
				for(vint i=0;i<children.Count();i++)
				{
					children[i]->OnParentLineChanged();
				}
			}

			void GuiControl::OnRenderTargetChanged(elements::IGuiGraphicsRenderTarget* renderTarget)
			{
				GuiControlSignalEventArgs arguments(boundsComposition);
				arguments.controlSignal = ControlSignal::RenderTargetChanged;
				ControlSignalTrigerred.Execute(arguments);
			}

			void GuiControl::OnBeforeReleaseGraphicsHost()
			{
				// TODO: (enumerable) foreach
				for(vint i=0;i<children.Count();i++)
				{
					children[i]->OnBeforeReleaseGraphicsHost();
				}
			}

			void GuiControl::UpdateVisuallyEnabled()
			{
				bool newValue = isEnabled && (parent == 0 ? true : parent->GetVisuallyEnabled());
				if (isVisuallyEnabled != newValue)
				{
					isVisuallyEnabled = newValue;

					if (!isVisuallyEnabled && isFocused)
					{
						GuiControl* selectedControl = nullptr;
						auto current = GetParent();
						while (current)
						{
							if (current->GetFocusableComposition() && current->GetVisuallyEnabled())
							{
								selectedControl = current;
								break;
							}
							current = current->GetParent();
						}

						if (selectedControl)
						{
							selectedControl->SetFocused();
						}
						else if(auto host = focusableComposition->GetRelatedGraphicsHost())
						{
							host->ClearFocus();
						}
					}

					if (controlTemplateObject)
					{
						controlTemplateObject->SetVisuallyEnabled(isVisuallyEnabled);
					}
					VisuallyEnabledChanged.Execute(GetNotifyEventArguments());

					// TODO: (enumerable) foreach
					for (vint i = 0; i < children.Count(); i++)
					{
						children[i]->UpdateVisuallyEnabled();
					}
				}
			}

			void GuiControl::UpdateDisplayFont()
			{
				auto newValue =
					font ? font.Value() :
					parent ? parent->GetDisplayFont() :
					GetCurrentController()->ResourceService()->GetDefaultFont();

				if (displayFont != newValue)
				{
					displayFont = newValue;
					if (controlTemplateObject)
					{
						controlTemplateObject->SetFont(displayFont);
					}
					DisplayFontChanged.Execute(GetNotifyEventArguments());

					// TODO: (enumerable) foreach
					for (vint i = 0; i < children.Count(); i++)
					{
						children[i]->UpdateDisplayFont();
					}
				}
			}

			void GuiControl::OnGotFocus(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (!isFocused)
				{
					isFocused = true;
					if (controlTemplateObject)
					{
						controlTemplateObject->SetFocused(true);
					}
					FocusedChanged.Execute(GetNotifyEventArguments());
				}
			}

			void GuiControl::OnLostFocus(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (isFocused)
				{
					isFocused = false;
					if (controlTemplateObject)
					{
						controlTemplateObject->SetFocused(false);
					}
					FocusedChanged.Execute(GetNotifyEventArguments());
				}
			}

			void GuiControl::SetFocusableComposition(compositions::GuiGraphicsComposition* value)
			{
				if (focusableComposition != value)
				{
					if (focusableComposition)
					{
						focusableComposition->GetEventReceiver()->gotFocus.Detach(gotFocusHandler);
						focusableComposition->GetEventReceiver()->lostFocus.Detach(lostFocusHandler);

						gotFocusHandler = nullptr;
						lostFocusHandler = nullptr;
					}

					focusableComposition = value;
					if (controlTemplateObject)
					{
						controlTemplateObject->SetFocusableComposition(focusableComposition);
					}

					if (focusableComposition)
					{
						gotFocusHandler = focusableComposition->GetEventReceiver()->gotFocus.AttachMethod(this, &GuiControl::OnGotFocus);
						lostFocusHandler = focusableComposition->GetEventReceiver()->lostFocus.AttachMethod(this, &GuiControl::OnLostFocus);
					}
					else
					{
						GuiEventArgs arguments(boundsComposition);
						OnLostFocus(boundsComposition, arguments);
					}
				}
			}

			bool GuiControl::IsControlVisibleAndEnabled()
			{
				GuiControl* control = this;
				while (control)
				{
					if (!control->GetVisible() || !control->GetEnabled())
					{
						return false;
					}
					control = control->GetParent();
				}
				return true;
			}

			bool GuiControl::IsAltEnabled()
			{
				return IsControlVisibleAndEnabled();
			}

			bool GuiControl::IsAltAvailable()
			{
				return focusableComposition != nullptr && alt != L"";
			}

			compositions::GuiGraphicsComposition* GuiControl::GetAltComposition()
			{
				return boundsComposition;
			}

			compositions::IGuiAltActionHost* GuiControl::GetActivatingAltHost()
			{
				return activatingAltHost;
			}

			void GuiControl::OnActiveAlt()
			{
				SetFocused();
			}

			bool GuiControl::IsTabEnabled()
			{
				return IsControlVisibleAndEnabled();
			}

			bool GuiControl::IsTabAvailable()
			{
				return focusableComposition != nullptr;
			}

			bool GuiControl::SharedPtrDestructorProc(DescriptableObject* obj, bool forceDisposing)
			{
				GuiControl* value=dynamic_cast<GuiControl*>(obj);
				if(value->GetBoundsComposition()->GetParent())
				{
					if (!forceDisposing) return false;
				}
				SafeDeleteControl(value);
				return true;
			}

			GuiControl::GuiControl(theme::ThemeName themeName)
				:controlThemeName(themeName)
			{
				if (auto controller = GetCurrentController())
				{
					displayFont = controller->ResourceService()->GetDefaultFont();
				}

				{
					boundsComposition = new GuiBoundsComposition;
					boundsComposition->SetAssociatedControl(this);
					boundsComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

					containerComposition = new GuiBoundsComposition;
					containerComposition->SetTransparentToMouse(true);
					containerComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					containerComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));

					boundsComposition->AddChild(containerComposition);
				}
				{
					ControlThemeNameChanged.SetAssociatedComposition(boundsComposition);
					ControlTemplateChanged.SetAssociatedComposition(boundsComposition);
					ControlSignalTrigerred.SetAssociatedComposition(boundsComposition);
					VisibleChanged.SetAssociatedComposition(boundsComposition);
					EnabledChanged.SetAssociatedComposition(boundsComposition);
					FocusedChanged.SetAssociatedComposition(boundsComposition);
					VisuallyEnabledChanged.SetAssociatedComposition(boundsComposition);
					DisplayFontChanged.SetAssociatedComposition(boundsComposition);
					AltChanged.SetAssociatedComposition(boundsComposition);
					TextChanged.SetAssociatedComposition(boundsComposition);
					FontChanged.SetAssociatedComposition(boundsComposition);
					ContextChanged.SetAssociatedComposition(boundsComposition);
				}
				sharedPtrDestructorProc = &GuiControl::SharedPtrDestructorProc;
			}

			GuiControl::~GuiControl()
			{
				if (disposedFlag)
				{
					disposedFlag->SetDisposed();
				}
				// prevent a root bounds composition from notifying its dead controls
				if (!parent)
				{
					NotifyFinalizeInstance(boundsComposition);
				}

				if (tooltipControl)
				{
					// the only legal parent is the GuiApplication::sharedTooltipWindow
					if (tooltipControl->GetBoundsComposition()->GetParent())
					{
						tooltipControl->GetBoundsComposition()->GetParent()->RemoveChild(tooltipControl->GetBoundsComposition());
					}
					delete tooltipControl;
				}

				// TODO: (enumerable) foreach
				for (vint i = 0; i < children.Count(); i++)
				{
					delete children[i];
				}
				children.Clear();

				// let the root control of a control tree delete the whole composition tree
				if (!parent)
				{
					delete boundsComposition;
				}
			}

			void GuiControl::TryDelayExecuteIfNotDeleted(Func<void()> proc)
			{
				if (auto controlHost = GetRelatedControlHost())
				{
					auto flag = GetDisposedFlag();
					GetApplication()->InvokeInMainThread(controlHost, [=]()
					{
						if (!flag->IsDisposed())
						{
							proc();
						}
					});
				}
				else
				{
					proc();
				}
			}

			compositions::GuiEventArgs GuiControl::GetNotifyEventArguments()
			{
				return GuiEventArgs(boundsComposition);
			}

			theme::ThemeName GuiControl::GetControlThemeName()
			{
				return controlThemeName;
			}

			void GuiControl::SetControlThemeName(theme::ThemeName value)
			{
				SetControlThemeNameAndTemplate(value, controlTemplate);
			}

			GuiControl::ControlTemplatePropertyType GuiControl::GetControlTemplate()
			{
				return controlTemplate;
			}

			void GuiControl::SetControlTemplate(const ControlTemplatePropertyType& value)
			{
				SetControlThemeNameAndTemplate(controlThemeName, value);
			}

			void GuiControl::SetControlThemeNameAndTemplate(theme::ThemeName themeNameValue, const ControlTemplatePropertyType& controlTemplateValue)
			{
				bool themeChanged = (controlThemeName != themeNameValue);
				bool templateChanged = (controlTemplate || controlTemplateValue);
				if (themeChanged || templateChanged)
				{
					controlThemeName = themeNameValue;
					controlTemplate = controlTemplateValue;
					RebuildControlTemplate();
					
					if (themeChanged)
					{
						ControlThemeNameChanged.Execute(GetNotifyEventArguments());
					}
					if (templateChanged)
					{
						ControlTemplateChanged.Execute(GetNotifyEventArguments());
					}
				}
			}

			templates::GuiControlTemplate* GuiControl::GetControlTemplateObject()
			{
				EnsureControlTemplateExists();
				return controlTemplateObject;
			}

			compositions::GuiBoundsComposition* GuiControl::GetBoundsComposition()
			{
				EnsureControlTemplateExists();
				return boundsComposition;
			}

			compositions::GuiGraphicsComposition* GuiControl::GetContainerComposition()
			{
				EnsureControlTemplateExists();
				return containerComposition;
			}

			compositions::GuiGraphicsComposition* GuiControl::GetFocusableComposition()
			{
				EnsureControlTemplateExists();
				return focusableComposition;
			}

			GuiControl* GuiControl::GetParent()
			{
				return parent;
			}

			vint GuiControl::GetChildrenCount()
			{
				return children.Count();
			}

			GuiControl* GuiControl::GetChild(vint index)
			{
				return children[index];
			}

			bool GuiControl::AddChild(GuiControl* control)
			{
				return GetContainerComposition()->AddChild(control->GetBoundsComposition());
			}

			bool GuiControl::HasChild(GuiControl* control)
			{
				return children.Contains(control);
			}

			GuiControlHost* GuiControl::GetRelatedControlHost()
			{
				return parent?parent->GetRelatedControlHost():0;
			}

			bool GuiControl::GetVisuallyEnabled()
			{
				return isVisuallyEnabled;
			}

			bool GuiControl::GetFocused()
			{
				return isFocused;
			}

			void GuiControl::SetFocused()
			{
				if (!focusableComposition) return;
				if (!isVisuallyEnabled) return;
				if (!focusableComposition->GetEventuallyVisible()) return;

				if (auto host = focusableComposition->GetRelatedGraphicsHost())
				{
					host->SetFocus(focusableComposition);
				}
			}

			bool GuiControl::GetAcceptTabInput()
			{
				return acceptTabInput;
			}

			void GuiControl::SetAcceptTabInput(bool value)
			{
				acceptTabInput = value;
			}

			vint GuiControl::GetTabPriority()
			{
				return tabPriority;
			}

			void GuiControl::SetTabPriority(vint value)
			{
				vint newTabPriority = value < 0 ? -1 : value;
				if (tabPriority != newTabPriority)
				{
					tabPriority = newTabPriority;
					if (auto host = boundsComposition->GetRelatedGraphicsHost())
					{
						host->InvalidateTabOrderCache();
					}
				}
			}

			bool GuiControl::GetEnabled()
			{
				return isEnabled;
			}

			void GuiControl::SetEnabled(bool value)
			{
				if(isEnabled!=value)
				{
					isEnabled=value;
					EnabledChanged.Execute(GetNotifyEventArguments());
					UpdateVisuallyEnabled();
				}
			}

			bool GuiControl::GetVisible()
			{
				return isVisible;
			}

			void GuiControl::SetVisible(bool value)
			{
				boundsComposition->SetVisible(value);
				if(isVisible!=value)
				{
					isVisible=value;
					VisibleChanged.Execute(GetNotifyEventArguments());
				}
			}

			const WString& GuiControl::GetAlt()
			{
				return alt;
			}

			bool GuiControl::SetAlt(const WString& value)
			{
				if (!IGuiAltAction::IsLegalAlt(value)) return false;
				if (alt != value)
				{
					alt = value;
					AltChanged.Execute(GetNotifyEventArguments());
				}
				return true;
			}

			void GuiControl::SetActivatingAltHost(compositions::IGuiAltActionHost* host)
			{
				activatingAltHost = host;
			}

			const WString& GuiControl::GetText()
			{
				return text;
			}

			void GuiControl::SetText(const WString& value)
			{
				if (text != value)
				{
					text = value;
					if (controlTemplateObject)
					{
						controlTemplateObject->SetText(text);
					}
					TextChanged.Execute(GetNotifyEventArguments());
				}
			}

			const Nullable<FontProperties>& GuiControl::GetFont()
			{
				return font;
			}

			void GuiControl::SetFont(const Nullable<FontProperties>& value)
			{
				if (font != value)
				{
					font = value;
					FontChanged.Execute(GetNotifyEventArguments());
					UpdateDisplayFont();
				}
			}

			const FontProperties& GuiControl::GetDisplayFont()
			{
				return displayFont;
			}
			
			description::Value GuiControl::GetContext()
			{
				return context;
			}

			void GuiControl::SetContext(const description::Value& value)
			{
				if (context != value)
				{
					context = value;
					if (controlTemplateObject)
					{
						controlTemplateObject->SetContext(context);
					}
					ContextChanged.Execute(GetNotifyEventArguments());
				}
			}

			description::Value GuiControl::GetTag()
			{
				return tag;
			}

			void GuiControl::SetTag(const description::Value& value)
			{
				tag=value;
			}

			GuiControl* GuiControl::GetTooltipControl()
			{
				return tooltipControl;
			}

			GuiControl* GuiControl::SetTooltipControl(GuiControl* value)
			{
				GuiControl* oldTooltipControl=tooltipControl;
				tooltipControl=value;
				return oldTooltipControl;
			}

			vint GuiControl::GetTooltipWidth()
			{
				return tooltipWidth;
			}

			void GuiControl::SetTooltipWidth(vint value)
			{
				tooltipWidth=value;
			}

			bool GuiControl::DisplayTooltip(Point location)
			{
				if(!tooltipControl) return false;
				GetApplication()->ShowTooltip(this, tooltipControl, tooltipWidth, location);
				return true;
			}

			void GuiControl::CloseTooltip()
			{
				if(GetApplication()->GetTooltipOwner()==this)
				{
					GetApplication()->CloseTooltip();
				}
			}

			IDescriptable* GuiControl::QueryService(const WString& identifier)
			{
				if (identifier == IGuiAltAction::Identifier)
				{
					return (IGuiAltAction*)this;
				}
				else if (identifier == IGuiAltActionContainer::Identifier)
				{
					return nullptr;
				}
				else if (identifier == IGuiTabAction::Identifier)
				{
					return (IGuiTabAction*)this;
				}
				else
				{
					vint index = controlServices.Keys().IndexOf(identifier);
					if (index != -1)
					{
						return controlServices.Values()[index].Obj();
					}

					if (parent)
					{
						return parent->QueryService(identifier);
					}
				}
				return nullptr;
			}

			bool GuiControl::AddService(const WString& identifier, Ptr<IDescriptable> value)
			{
				if (controlServices.Keys().Contains(identifier))
				{
					return false;
				}

				controlServices.Add(identifier, value);
				OnServiceAdded();
				return true;
			}

/***********************************************************************
GuiCustomControl
***********************************************************************/

			controls::GuiControlHost* GuiCustomControl::GetControlHostForInstance()
			{
				return GetRelatedControlHost();
			}

			void GuiCustomControl::OnParentLineChanged()
			{
				GuiControl::OnParentLineChanged();
				OnControlHostForInstanceChanged();
			}

			GuiCustomControl::GuiCustomControl(theme::ThemeName themeName)
				:GuiControl(themeName)
			{
			}

			GuiCustomControl::~GuiCustomControl()
			{
				FinalizeAggregation();
				FinalizeInstanceRecursively(this);
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\CONTROLS\GUIINSTANCEROOTOBJECT.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace reflection::description;
			using namespace compositions;

/***********************************************************************
GuiComponent
***********************************************************************/
			
			GuiComponent::GuiComponent()
			{
			}

			GuiComponent::~GuiComponent()
			{
			}

			void GuiComponent::Attach(GuiInstanceRootObject* rootObject)
			{
			}

			void GuiComponent::Detach(GuiInstanceRootObject* rootObject)
			{
			}

/***********************************************************************
GuiInstanceRootObject
***********************************************************************/

			class RootObjectTimerCallback : public Object, public IGuiGraphicsTimerCallback
			{
			public:
				GuiControlHost*					controlHost;
				GuiInstanceRootObject*			rootObject;
				bool							alive = true;

				RootObjectTimerCallback(GuiInstanceRootObject* _rootObject, GuiControlHost* _controlHost)
					:rootObject(_rootObject)
					, controlHost(_controlHost)
				{
				}

				bool Play()override
				{
					if (alive)
					{
						// TODO: (enumerable) foreach:indexed(alterable(reversed))
						for (vint i = rootObject->runningAnimations.Count() - 1; i >= 0; i--)
						{
							auto animation = rootObject->runningAnimations[i];
							animation->Run();
							if (animation->GetStopped())
							{
								rootObject->runningAnimations.RemoveAt(i);
							}
						}

						if (rootObject->runningAnimations.Count() == 0)
						{
							rootObject->UninstallTimerCallback(nullptr);
							return false;
						}
					}
					return alive;
				}
			};
			
			void GuiInstanceRootObject::InstallTimerCallback(controls::GuiControlHost* controlHost)
			{
				if (!timerCallback)
				{
					timerCallback = Ptr(new RootObjectTimerCallback(this, controlHost));
					controlHost->GetTimerManager()->AddCallback(timerCallback);
				}
			}

			bool GuiInstanceRootObject::UninstallTimerCallback(controls::GuiControlHost* controlHost)
			{
				if (timerCallback && timerCallback->controlHost != controlHost)
				{
					timerCallback->alive = false;
					timerCallback = nullptr;
					return true;
				}
				return false;
			}

			void GuiInstanceRootObject::OnControlHostForInstanceChanged()
			{
				auto controlHost = GetControlHostForInstance();
				if (UninstallTimerCallback(controlHost))
				{
					for (auto animation : runningAnimations)
					{
						animation->Pause();
					}
				}

				if (controlHost)
				{
					InstallTimerCallback(controlHost);
					for (auto animation : runningAnimations)
					{
						animation->Resume();
					}
					StartPendingAnimations();
				}
			}

			void GuiInstanceRootObject::StartPendingAnimations()
			{
				for (auto animation : pendingAnimations)
				{
					animation->Start();
				}

				CopyFrom(runningAnimations, pendingAnimations, true);
				pendingAnimations.Clear();
			}

			GuiInstanceRootObject::GuiInstanceRootObject()
			{
			}

			GuiInstanceRootObject::~GuiInstanceRootObject()
			{
				UninstallTimerCallback(nullptr);
			}

			void GuiInstanceRootObject::FinalizeInstance()
			{
				if (!finalized)
				{
					finalized = true;

					for (auto subscription : subscriptions)
					{
						subscription->Close();
					}
					for (auto component : components)
					{
						component->Detach(this);
					}

					subscriptions.Clear();
					// TODO: (enumerable) foreach
					for (vint i = 0; i<components.Count(); i++)
					{
						delete components[i];
					}
					components.Clear();
				}
			}

			bool GuiInstanceRootObject::IsFinalized()
			{
				return finalized;
			}

			void GuiInstanceRootObject::FinalizeInstanceRecursively(templates::GuiTemplate* thisObject)
			{
				if (!finalized)
				{
					NotifyFinalizeInstance(thisObject);
				}
			}

			void GuiInstanceRootObject::FinalizeInstanceRecursively(GuiCustomControl* thisObject)
			{
				if (!finalized)
				{
					NotifyFinalizeInstance(thisObject);
				}
			}

			void GuiInstanceRootObject::FinalizeInstanceRecursively(GuiControlHost* thisObject)
			{
				if (!finalized)
				{
					NotifyFinalizeInstance(thisObject);
				}
			}

			void GuiInstanceRootObject::FinalizeGeneralInstance(GuiInstanceRootObject* thisObject)
			{
			}

			void GuiInstanceRootObject::SetResourceResolver(Ptr<GuiResourcePathResolver> resolver)
			{
				resourceResolver = resolver;
			}

			Ptr<DescriptableObject> GuiInstanceRootObject::ResolveResource(const WString& protocol, const WString& path, bool ensureExist)
			{
				Ptr<DescriptableObject> object;
				if (resourceResolver)
				{
					object = resourceResolver->ResolveResource(protocol, path);
				}
				if (ensureExist && !object)
				{
					throw ArgumentException(L"Resource \"" + protocol + L"://" + path + L"\" does not exist.");
				}
				return object;
			}

			Ptr<description::IValueSubscription> GuiInstanceRootObject::AddSubscription(Ptr<description::IValueSubscription> subscription)
			{
				CHECK_ERROR(finalized == false, L"GuiInstanceRootObject::AddSubscription(Ptr<IValueSubscription>)#Cannot add subscription after finalizing.");
				if (subscriptions.Contains(subscription.Obj()))
				{
					return nullptr;
				}
				else
				{
					subscriptions.Add(subscription);
					subscription->Open();
					subscription->Update();
					return subscription;
				}
			}

			void GuiInstanceRootObject::UpdateSubscriptions()
			{
				for (auto subscription : subscriptions)
				{
					subscription->Update();
				}
			}

			bool GuiInstanceRootObject::AddComponent(GuiComponent* component)
			{
				CHECK_ERROR(finalized == false, L"GuiInstanceRootObject::AddComponent(GuiComponent*)#Cannot add component after finalizing.");
				if(components.Contains(component))
				{
					return false;
				}
				else
				{
					components.Add(component);
					component->Attach(this);
					return true;
				}
			}

			bool GuiInstanceRootObject::AddControlHostComponent(GuiControlHost* controlHost)
			{
				return AddComponent(new GuiObjectComponent<GuiControlHost>(Ptr(controlHost)));
			}

			bool GuiInstanceRootObject::AddAnimation(Ptr<IGuiAnimation> animation)
			{
				CHECK_ERROR(finalized == false, L"GuiInstanceRootObject::AddAnimation(Ptr<IGuiAnimation>)#Cannot add animation after finalizing.");
				if (runningAnimations.Contains(animation.Obj()) || pendingAnimations.Contains(animation.Obj()))
				{
					return false;
				}
				else
				{
					pendingAnimations.Add(animation);

					if (auto controlHost = GetControlHostForInstance())
					{
						InstallTimerCallback(controlHost);
						StartPendingAnimations();
					}
					return true;
				}
			}

			bool GuiInstanceRootObject::KillAnimation(Ptr<IGuiAnimation> animation)
			{
				if (!animation) return false;
				if (runningAnimations.Contains(animation.Obj()))
				{
					runningAnimations.Remove(animation.Obj());
					return true;
				}
				if (pendingAnimations.Contains(animation.Obj()))
				{
					pendingAnimations.Remove(animation.Obj());
					return true;
				}
				return false;
			}

			reflection::description::Value GuiInstanceRootObject::GetNamedObject(const WString& name)
			{
				vint index = namedObjects.Keys().IndexOf(name);
				if (index == -1)
				{
					return {};
				}
				else
				{
					return namedObjects.Values()[index];
				}
			}

			void GuiInstanceRootObject::SetNamedObject(const WString& name, const reflection::description::Value& namedObject)
			{
				namedObjects.Set(name, namedObject);
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\CONTROLS\GUILABELCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace elements;
			using namespace compositions;
			using namespace collections;
			using namespace reflection::description;

/***********************************************************************
GuiLabel
***********************************************************************/

			void GuiLabel::BeforeControlTemplateUninstalled_()
			{
				auto ct = TypedControlTemplateObject(false);
				if (!ct) return;

				textColorConsisted = (textColor == ct->GetDefaultTextColor());
			}

			void GuiLabel::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				if (initialize || textColorConsisted)
				{
					SetTextColor(ct->GetDefaultTextColor());
				}
				else
				{
					ct->SetTextColor(textColor);
				}
			}

			GuiLabel::GuiLabel(theme::ThemeName themeName)
				:GuiControl(themeName)
			{
			}

			GuiLabel::~GuiLabel()
			{
			}

			Color GuiLabel::GetTextColor()
			{
				return textColor;
			}

			void GuiLabel::SetTextColor(Color value)
			{
				if (textColor != value)
				{
					textColor = value;
					TypedControlTemplateObject(true)->SetTextColor(textColor);
				}
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\CONTROLS\GUITHEMEMANAGER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace templates
		{

/***********************************************************************
GuiTemplate
***********************************************************************/

			GuiTemplate_PROPERTIES(GUI_TEMPLATE_PROPERTY_IMPL)

			controls::GuiControlHost* GuiTemplate::GetControlHostForInstance()
			{
				return GetRelatedControlHost();
			}

			void GuiTemplate::OnParentLineChanged()
			{
				GuiBoundsComposition::OnParentLineChanged();
				OnControlHostForInstanceChanged();
			}

			GuiTemplate::GuiTemplate()
			{
				GuiTemplate_PROPERTIES(GUI_TEMPLATE_PROPERTY_EVENT_INIT)
			}

			GuiTemplate::~GuiTemplate()
			{
				FinalizeInstanceRecursively(this);
			}

/***********************************************************************
Template Declarations
***********************************************************************/

			GUI_CORE_CONTROL_TEMPLATE_DECL(GUI_TEMPLATE_CLASS_IMPL)
		}
	}
}

/***********************************************************************
.\APPLICATION\CONTROLS\GUIWINDOWCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace elements;
			using namespace compositions;
			using namespace collections;
			using namespace reflection::description;

/***********************************************************************
GuiControlHost
***********************************************************************/

			void GuiControlHost::DeleteThis()
			{
				auto callback = callbackAfterDeleteThis;
				delete this;
				if (callback)
				{
					callback();
				}
			}

			void GuiControlHost::OnNativeWindowChanged()
			{
			}

			void GuiControlHost::OnVisualStatusChanged()
			{
			}

			controls::GuiControlHost* GuiControlHost::GetControlHostForInstance()
			{
				return this;
			}

			GuiControl* GuiControlHost::GetTooltipOwner(Point location)
			{
				GuiGraphicsComposition* composition=this->GetBoundsComposition()->FindVisibleComposition(location, true);
				if(composition)
				{
					GuiControl* control=composition->GetRelatedControl();
					while(control)
					{
						if(control->GetTooltipControl())
						{
							return control;
						}
						control=control->GetParent();
					}
				}
				return nullptr;
			}

			void GuiControlHost::MoveIntoTooltipControl(GuiControl* tooltipControl, Point location)
			{
				if (tooltipLocation != location)
				{
					tooltipLocation = location;
					{
						GuiControl* currentOwner = GetApplication()->GetTooltipOwner();
						if (currentOwner && currentOwner != tooltipControl)
						{
							if (tooltipCloseDelay)
							{
								tooltipCloseDelay->Cancel();
								tooltipCloseDelay = 0;
							}
							GetApplication()->DelayExecuteInMainThread([=]()
							{
								currentOwner->CloseTooltip();
							}, TooltipDelayCloseTime);
						}
					}
					if (!tooltipControl)
					{
						if (tooltipOpenDelay)
						{
							tooltipOpenDelay->Cancel();
							tooltipOpenDelay = 0;
						}
					}
					else if (tooltipOpenDelay)
					{
						tooltipOpenDelay->Delay(TooltipDelayOpenTime);
					}
					else if (GetApplication()->GetTooltipOwner() != tooltipControl)
					{
						tooltipOpenDelay = GetApplication()->DelayExecuteInMainThread([this]()
						{
							GuiControl* owner = GetTooltipOwner(tooltipLocation);
							if (owner)
							{
								Point offset = owner->GetBoundsComposition()->GetGlobalBounds().LeftTop();
								Point p(tooltipLocation.x - offset.x, tooltipLocation.y - offset.y + 24);
								owner->DisplayTooltip(p);
								tooltipOpenDelay = 0;

								tooltipCloseDelay = GetApplication()->DelayExecuteInMainThread([this, owner]()
								{
									owner->CloseTooltip();
								}, TooltipDelayLifeTime);
							}
						}, TooltipDelayOpenTime);
					}
				}
			}

			void GuiControlHost::MouseMoving(const NativeWindowMouseInfo& info)
			{
				if (!info.left && !info.middle && !info.right)
				{
					auto location = Point(host->GetNativeWindow()->Convert(NativePoint(info.x, info.y)));
					GuiControl* tooltipControl = GetTooltipOwner(location);
					MoveIntoTooltipControl(tooltipControl, location);
				}
			}

			void GuiControlHost::MouseLeaved()
			{
				MoveIntoTooltipControl(0, Point(-1, -1));
			}

			void GuiControlHost::Moved()
			{
				OnVisualStatusChanged();
			}

			void GuiControlHost::Enabled()
			{
				GuiControl::SetEnabled(true);
				OnVisualStatusChanged();
			}

			void GuiControlHost::Disabled()
			{
				GuiControl::SetEnabled(false);
				OnVisualStatusChanged();
			}

			void GuiControlHost::GotFocus()
			{
				WindowGotFocus.Execute(GetNotifyEventArguments());
				OnVisualStatusChanged();
			}

			void GuiControlHost::LostFocus()
			{
				WindowLostFocus.Execute(GetNotifyEventArguments());
				OnVisualStatusChanged();
			}

			void GuiControlHost::RenderingAsActivated()
			{
				WindowActivated.Execute(GetNotifyEventArguments());
				OnVisualStatusChanged();
			}

			void GuiControlHost::RenderingAsDeactivated()
			{
				WindowDeactivated.Execute(GetNotifyEventArguments());
				OnVisualStatusChanged();
			}

			void GuiControlHost::Opened()
			{
				WindowOpened.Execute(GetNotifyEventArguments());
			}

			void GuiControlHost::BeforeClosing(bool& cancel)
			{
				GuiRequestEventArgs arguments(boundsComposition);
				arguments.cancel=cancel;
				WindowClosing.Execute(arguments);
				if(!arguments.handled)
				{
					cancel=arguments.cancel;
				}
			}

			void GuiControlHost::AfterClosing()
			{
				WindowReadyToClose.Execute(GetNotifyEventArguments());
			}

			void GuiControlHost::Closed()
			{
				WindowClosed.Execute(GetNotifyEventArguments());
			}

			void GuiControlHost::Destroying()
			{
				WindowDestroying.Execute(GetNotifyEventArguments());
				calledDestroyed = true;
				if (deleteWhenDestroyed)
				{
					GetApplication()->InvokeInMainThread(this, [=, this]()
					{
						DeleteThis();
					});
				}
				SetNativeWindow(nullptr);
			}

			void GuiControlHost::UpdateClientSize(Size value, bool updateNativeWindowOnly)
			{
				if (auto window = host->GetNativeWindow())
				{
					host->GetNativeWindow()->SetClientSize(window->Convert(value));
					if (!updateNativeWindowOnly)
					{
						host->RequestUpdateSizeFromNativeWindow();
					}
				}
			}

			void GuiControlHost::UpdateClientSizeAfterRendering(Size preferredSize, Size clientSize)
			{
				auto size = GetClientSize();
				if (size != clientSize)
				{
					UpdateClientSize(clientSize, true);
				}
			}

			GuiControlHost::GuiControlHost(theme::ThemeName themeName, INativeWindow::WindowMode mode)
				:GuiControl(themeName)
				, windowMode(mode)
			{
				boundsComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				
				WindowGotFocus.SetAssociatedComposition(boundsComposition);
				WindowLostFocus.SetAssociatedComposition(boundsComposition);
				WindowActivated.SetAssociatedComposition(boundsComposition);
				WindowDeactivated.SetAssociatedComposition(boundsComposition);
				WindowOpened.SetAssociatedComposition(boundsComposition);
				WindowClosing.SetAssociatedComposition(boundsComposition);
				WindowReadyToClose.SetAssociatedComposition(boundsComposition);
				WindowClosed.SetAssociatedComposition(boundsComposition);
				WindowDestroying.SetAssociatedComposition(boundsComposition);

				host=new GuiGraphicsHost(this, boundsComposition);
				sharedPtrDestructorProc = 0;
			}

			GuiControlHost::~GuiControlHost()
			{
				FinalizeInstanceRecursively(this);
				OnBeforeReleaseGraphicsHost();
				delete host;
			}

			void GuiControlHost::DeleteAfterProcessingAllEvents(const Func<void()>& callback)
			{
				CHECK_ERROR(!deleteWhenDestroyed, L"vl::presentation::controls::GuiControlHost::DeleteAfterProcessingAllEvents()#This function cannot be called twice.");
				deleteWhenDestroyed = true;
				callbackAfterDeleteThis = callback;

				auto window = host->GetNativeWindow();
				if (calledDestroyed || !window)
				{
					DeleteThis();
				}
				else
				{
					GetApplication()->InvokeInMainThread(this, [window]()
					{
						GetCurrentController()->WindowService()->DestroyNativeWindow(window);
					});
				}
			}

			compositions::GuiGraphicsHost* GuiControlHost::GetGraphicsHost()
			{
				return host;
			}

			compositions::GuiGraphicsComposition* GuiControlHost::GetMainComposition()
			{
				return host->GetMainComposition();
			}

			INativeWindow* GuiControlHost::GetNativeWindow()
			{
				return host->GetNativeWindow();
			}

			void GuiControlHost::SetNativeWindow(INativeWindow* window)
			{
				auto previousNativeWindow = host->GetNativeWindow();
				if(previousNativeWindow)
				{
					host->GetNativeWindow()->UninstallListener(this);
				}
				if (window)
				{
					if (windowMode != window->GetWindowMode())
					{
						CHECK_FAIL(L"GuiControlHost::SetNativeWindow(INativeWindow*)#Window mode does not match.");
					}
				}
				host->SetNativeWindow(window);
				if(host->GetNativeWindow())
				{
					host->GetNativeWindow()->InstallListener(this);
				}
				GetApplication()->NotifyNativeWindowChanged(this, previousNativeWindow);
				OnNativeWindowChanged();
			}

			void GuiControlHost::ForceCalculateSizeImmediately()
			{
				auto size = GetClientSize();
				boundsComposition->ForceCalculateSizeImmediately();
				SetClientSize(size);
			}

			bool GuiControlHost::GetEnabled()
			{
				if(host->GetNativeWindow())
				{
					return host->GetNativeWindow()->IsEnabled();
				}
				else
				{
					return false;
				}
			}

			void GuiControlHost::SetEnabled(bool value)
			{
				if(host->GetNativeWindow())
				{
					if(value)
					{
						host->GetNativeWindow()->Enable();
					}
					else
					{
						host->GetNativeWindow()->Disable();
					}
				}
			}

			bool GuiControlHost::GetFocused()
			{
				if(host->GetNativeWindow())
				{
					return host->GetNativeWindow()->IsActivated();
				}
				else
				{
					return false;
				}
			}

			void GuiControlHost::SetFocused()
			{
				if(host->GetNativeWindow())
				{
					host->GetNativeWindow()->SetActivate();
				}
			}

			bool GuiControlHost::GetRenderingAsActivated()
			{
				if(host->GetNativeWindow())
				{
					return host->GetNativeWindow()->IsRenderingAsActivated();
				}
				else
				{
					return false;
				}
			}

			bool GuiControlHost::GetShowInTaskBar()
			{
				if(host->GetNativeWindow())
				{
					return host->GetNativeWindow()->IsAppearedInTaskBar();
				}
				else
				{
					return false;
				}
			}

			void GuiControlHost::SetShowInTaskBar(bool value)
			{
				if(host->GetNativeWindow())
				{
					if(value)
					{
						host->GetNativeWindow()->ShowInTaskBar();
					}
					else
					{
						host->GetNativeWindow()->HideInTaskBar();
					}
				}
			}

			bool GuiControlHost::GetEnabledActivate()
			{
				if(host->GetNativeWindow())
				{
					return host->GetNativeWindow()->IsEnabledActivate();
				}
				else
				{
					return false;
				}
			}

			void GuiControlHost::SetEnabledActivate(bool value)
			{
				if(host->GetNativeWindow())
				{
					if(value)
					{
						host->GetNativeWindow()->EnableActivate();
					}
					else
					{
						host->GetNativeWindow()->DisableActivate();
					}
				}
			}

			bool GuiControlHost::GetTopMost()
			{
				if(host->GetNativeWindow())
				{
					return host->GetNativeWindow()->GetTopMost();
				}
				else
				{
					return false;
				}
			}

			void GuiControlHost::SetTopMost(bool topmost)
			{
				if(host->GetNativeWindow())
				{
					host->GetNativeWindow()->SetTopMost(topmost);
				}
			}

			compositions::IGuiShortcutKeyManager* GuiControlHost::GetShortcutKeyManager()
			{
				return host->GetShortcutKeyManager();
			}

			void GuiControlHost::SetShortcutKeyManager(compositions::IGuiShortcutKeyManager* value)
			{
				host->SetShortcutKeyManager(value);
			}

			compositions::GuiGraphicsTimerManager* GuiControlHost::GetTimerManager()
			{
				return host->GetTimerManager();
			}

			Size GuiControlHost::GetClientSize()
			{
				if (auto window = host->GetNativeWindow())
				{
					return window->Convert(window->GetClientSize());
				}
				else
				{
					return Size(0, 0);
				}
			}

			void GuiControlHost::SetClientSize(Size value)
			{
				UpdateClientSize(value, false);
			}

			NativePoint GuiControlHost::GetLocation()
			{
				if(auto window = host->GetNativeWindow())
				{
					return window->GetBounds().LeftTop();
				}
				else
				{
					return NativePoint();
				}
			}

			void GuiControlHost::SetLocation(NativePoint value)
			{
				if (auto window = host->GetNativeWindow())
				{
					auto bounds = window->GetBounds();
					window->SetBounds(NativeRect(value, bounds.GetSize()));
				}
			}

			void GuiControlHost::SetBounds(NativePoint location, Size size)
			{
				if (auto window = host->GetNativeWindow())
				{
					window->SetBounds(NativeRect(location, window->Convert(size)));
				}
			}

			GuiControlHost* GuiControlHost::GetRelatedControlHost()
			{
				return this;
			}

			const WString& GuiControlHost::GetText()
			{
				WString result;
				if(host->GetNativeWindow())
				{
					result=host->GetNativeWindow()->GetTitle();
				}
				if(result!=GuiControl::GetText())
				{
					GuiControl::SetText(result);
				}
				return GuiControl::GetText();
			}

			void GuiControlHost::SetText(const WString& value)
			{
				if(host->GetNativeWindow())
				{
					host->GetNativeWindow()->SetTitle(value);
					GuiControl::SetText(value);
				}
			}

			INativeScreen* GuiControlHost::GetRelatedScreen()
			{
				if(host->GetNativeWindow())
				{
					return GetCurrentController()->ScreenService()->GetScreen(host->GetNativeWindow());
				}
				else
				{
					return 0;
				}
			}

			void GuiControlHost::Show()
			{
				if(host->GetNativeWindow())
				{
					host->GetNativeWindow()->Show();
				}
			}

			void GuiControlHost::ShowDeactivated()
			{
				if(host->GetNativeWindow())
				{
					host->GetNativeWindow()->ShowDeactivated();
				}
			}

			void GuiControlHost::ShowRestored()
			{
				if(host->GetNativeWindow())
				{
					host->GetNativeWindow()->ShowRestored();
				}
			}

			void GuiControlHost::ShowMaximized()
			{
				if(host->GetNativeWindow())
				{
					host->GetNativeWindow()->ShowMaximized();
				}
			}

			void GuiControlHost::ShowMinimized()
			{
				if(host->GetNativeWindow())
				{
					host->GetNativeWindow()->ShowMinimized();
				}
			}

			void GuiControlHost::Hide()
			{
				if (auto window = host->GetNativeWindow())
				{
					auto controller = GetCurrentController();
					if (window == controller->WindowService()->GetMainWindow())
					{
						controller->AutomationService()->Stop();
					}
					window->Hide(false);
				}
			}

			void GuiControlHost::Close()
			{
				if (auto window = host->GetNativeWindow())
				{
					window->Hide(true);
					// auto mainWindow = GetCurrentController()->WindowService()->GetMainWindow();
					// if (mainWindow == window)
					// {
					// 	SetNativeWindow(nullptr);
					// 	GetCurrentController()->WindowService()->DestroyNativeWindow(window);
					// }
					// else
					// {
					// 	window->Hide(true);
					// }
				}
			}

			bool GuiControlHost::GetOpening()
			{
				INativeWindow* window=host->GetNativeWindow();
				if(window)
				{
					return window->IsVisible();
				}
				return false;
			}

			void GuiControlHost::NotifyUpdateDisplayFont()
			{
				UpdateDisplayFont();
			}

/***********************************************************************
GuiWindow
***********************************************************************/

			void GuiWindow::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiWindow::AfterControlTemplateInstalled_(bool initialize)
			{
				ApplyFrameConfig();

				auto ct = TypedControlTemplateObject(true);
				auto window = GetNativeWindow();

				SetControlTemplateProperties();
				UpdateIcon(window, ct);
				UpdateCustomFramePadding(window, ct);

				if (window)
				{
					window->SetIcon(icon);
				}
				SetNativeWindowFrameProperties();
			}

			void GuiWindow::UpdateIcon(INativeWindow* window, templates::GuiWindowTemplate* ct)
			{
				ct->SetIcon(icon ? icon : window ? window->GetIcon() : nullptr);
			}

			void GuiWindow::UpdateCustomFramePadding(INativeWindow* window, templates::GuiWindowTemplate* ct)
			{
				if (window)
				{
					ct->SetCustomFramePadding(window->Convert(window->GetCustomFramePadding()));
				}
				else
				{
					ct->SetCustomFramePadding({8, 8, 8, 8});
				}
			}

			bool GuiWindow::IsRenderedAsMaximized()
			{
				auto nativeWindow = GetNativeWindow();
				if (nativeWindow && GetApplication()->GetMainWindow() == this)
				{
					if (auto hostedApp = GetHostedApplication())
					{
						nativeWindow = hostedApp->GetNativeWindowHost();
					}
				}
				return nativeWindow ? nativeWindow->GetSizeState() == INativeWindow::Maximized : false;
			}

			void GuiWindow::SetControlTemplateProperties()
			{
				if (auto ct = TypedControlTemplateObject(false))
				{
					ct->SetMaximizedBox(hasMaximizedBox);
					ct->SetMinimizedBox(hasMinimizedBox);
					ct->SetBorder(hasBorder);
					ct->SetSizeBox(hasSizeBox);
					ct->SetIconVisible(isIconVisible);
					ct->SetTitleBar(hasTitleBar);
					ct->SetMaximized(IsRenderedAsMaximized());
					ct->SetActivated(GetRenderingAsActivated());
				}
			}

			void GuiWindow::SetNativeWindowFrameProperties()
			{
				if (auto window = GetNativeWindow())
				{
					if (TypedControlTemplateObject(true)->GetCustomFrameEnabled())
					{
						window->EnableCustomFrameMode();
						window->SetBorder(false);
					}
					else
					{
						window->DisableCustomFrameMode();
						window->SetBorder(hasBorder);
					}

					window->SetMaximizedBox(hasMaximizedBox);
					window->SetMinimizedBox(hasMinimizedBox);
					window->SetSizeBox(hasSizeBox);
					window->SetIconVisible(isIconVisible);
					window->SetTitleBar(hasTitleBar);
				}
			}

			bool GuiWindow::ApplyFrameConfigOnVariable(BoolOption frameConfig, BoolOption templateConfig, bool& variable)
			{
				if (frameConfig == BoolOption::AlwaysTrue && templateConfig == BoolOption::AlwaysFalse)return false;
				if (frameConfig == BoolOption::AlwaysFalse && templateConfig == BoolOption::AlwaysTrue) return false;

				if (frameConfig == BoolOption::AlwaysTrue || templateConfig == BoolOption::AlwaysTrue)
				{
					variable = true;
				}
				else if (frameConfig == BoolOption::AlwaysFalse || templateConfig == BoolOption::AlwaysFalse)
				{
					variable = false;
				}

				return true;
			}

			void GuiWindow::ApplyFrameConfig()
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::GuiWindow::CheckCustomFrameAndControlTemplateCompatibility#"

#define FIX_WINDOW_PROPERTY(VARIABLE, NAME)\
				CHECK_ERROR(\
					ApplyFrameConfigOnVariable(\
						(frameConfig ? frameConfig->NAME ## Option : BoolOption::Customizable),\
						(ct ? ct->Get ## NAME ## Option() : BoolOption::Customizable),\
						VARIABLE\
						),\
					ERROR_MESSAGE_PREFIX L"Frame configuration and control template are not compatible on property \"" L ## #NAME L"\"."\
					);\

				auto ct = TypedControlTemplateObject(false);
				if (frameConfig && ct)
				{
					if (
						(frameConfig->CustomFrameEnabled == BoolOption::AlwaysTrue && !ct->GetCustomFrameEnabled()) ||
						(frameConfig->CustomFrameEnabled == BoolOption::AlwaysFalse && ct->GetCustomFrameEnabled())
						)
					{
						CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Frame configuration and control template are not compatible on property \"CustomFrameEnabled\".");
					}
				}

				FIX_WINDOW_PROPERTY(hasMaximizedBox, MaximizedBox)
				FIX_WINDOW_PROPERTY(hasMinimizedBox, MinimizedBox)
				FIX_WINDOW_PROPERTY(hasBorder, Border)
				FIX_WINDOW_PROPERTY(hasSizeBox, SizeBox)
				FIX_WINDOW_PROPERTY(isIconVisible, IconVisible)
				FIX_WINDOW_PROPERTY(hasTitleBar, TitleBar)

				auto window = GetNativeWindow();
				SetControlTemplateProperties();
				UpdateCustomFramePadding(window, ct);
				SetNativeWindowFrameProperties();

#undef FIX_WINDOW_PROPERTY

#undef ERROR_MESSAGE_PREFIX
			}

			void GuiWindow::Moved()
			{
				GuiControlHost::Moved();
				TypedControlTemplateObject(true)->SetMaximized(IsRenderedAsMaximized());
			}

			void GuiWindow::DpiChanged(bool preparing)
			{
				if (!preparing)
				{
					if (auto ct = TypedControlTemplateObject(false))
					{
						UpdateCustomFramePadding(GetNativeWindow(), ct);
					}
				}
			}

			void GuiWindow::Opened()
			{
				// Workaround:
				// Constructor calling SetNativeWindow skips AfterControlTemplateInstalled_ of all sub classes
				CallFixingMissingControlTemplateCallback();
				GuiControlHost::Opened();
				if (auto ct = TypedControlTemplateObject(false))
				{
					UpdateIcon(GetNativeWindow(), ct);
				}
			}

			void GuiWindow::BeforeClosing(bool& cancel)
			{
				if (GetHostedApplication() && this == GetApplication()->GetMainWindow())
				{
					GuiWindow* pickedWindow = nullptr;

					if (showModalRecord)
					{
						pickedWindow = showModalRecord->current;
					}
					else
					{
						for (auto window : From(GetApplication()->GetWindows()))
						{
							if (window->GetVisible() && window->showModalRecord)
							{
								pickedWindow = window->showModalRecord->current;
								break;
							}
						}
					}

					if (pickedWindow && pickedWindow != this)
					{
						if (pickedWindow->GetFocused())
						{
							pickedWindow->Hide();
						}
						else
						{
							pickedWindow->SetFocused();
						}
						cancel = true;
						return;
					}
				}
				GuiControlHost::BeforeClosing(cancel);
			}

			void GuiWindow::AssignFrameConfig(const NativeWindowFrameConfig& config)
			{
				frameConfig = &config;
				FrameConfigChanged.Execute(GetNotifyEventArguments());
				ApplyFrameConfig();
			}

			void GuiWindow::OnNativeWindowChanged()
			{
				SetNativeWindowFrameProperties();
				GuiControlHost::OnNativeWindowChanged();
			}

			void GuiWindow::OnVisualStatusChanged()
			{
				GuiControlHost::OnVisualStatusChanged();
			}

			void GuiWindow::OnWindowActivated(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (auto ct = TypedControlTemplateObject(false))
				{
					ct->SetActivated(true);
				}
			}

			void GuiWindow::OnWindowDeactivated(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (auto ct = TypedControlTemplateObject(false))
				{
					ct->SetActivated(false);
				}
			}

			GuiWindow::GuiWindow(theme::ThemeName themeName, INativeWindow::WindowMode mode)
				:GuiControlHost(themeName, mode)
			{
				SetAltComposition(boundsComposition);
				SetAltControl(this, true);

				INativeWindow* window = GetCurrentController()->WindowService()->CreateNativeWindow(windowMode);
				SetNativeWindow(window);
				GetApplication()->RegisterWindow(this);
				ClipboardUpdated.SetAssociatedComposition(boundsComposition);
				FrameConfigChanged.SetAssociatedComposition(boundsComposition);

				WindowActivated.AttachMethod(this, &GuiWindow::OnWindowActivated);
				WindowDeactivated.AttachMethod(this, &GuiWindow::OnWindowDeactivated);
			}

			GuiWindow::GuiWindow(theme::ThemeName themeName)
				:GuiWindow(themeName, INativeWindow::Normal)
			{
			}

			GuiWindow::~GuiWindow()
			{
				FinalizeAggregation();
				GetApplication()->UnregisterWindow(this);
				INativeWindow* window=host->GetNativeWindow();
				if(window)
				{
					SetNativeWindow(nullptr);
					GetCurrentController()->WindowService()->DestroyNativeWindow(window);
				}
			}

			IDescriptable* GuiWindow::QueryService(const WString& identifier)
			{
				if (identifier == IGuiAltActionHost::Identifier)
				{
					return (IGuiAltActionHost*)this;
				}
				else
				{
					return GuiControlHost::QueryService(identifier);
				}
			}

			void GuiWindow::MoveToScreenCenter()
			{
				MoveToScreenCenter(GetRelatedScreen());
			}

			void GuiWindow::MoveToScreenCenter(INativeScreen* screen)
			{
				if (screen)
				{
					if (auto window = host->GetNativeWindow())
					{
						NativeRect screenBounds = screen->GetClientBounds();
						NativeSize windowSize = window->GetBounds().GetSize();
						SetLocation(
							NativePoint(
								screenBounds.Left() + (screenBounds.Width() - windowSize.x) / 2,
								screenBounds.Top() + (screenBounds.Height() - windowSize.y) / 2
							)
						);
					}
				}
			}

			const NativeWindowFrameConfig& GuiWindow::GetFrameConfig()
			{
				return frameConfig ? *frameConfig : NativeWindowFrameConfig::Default;
			}

#define IMPL_WINDOW_PROPERTY(VARIABLE, NAME, CONDITION_BREAK) \
			bool GuiWindow::Get ## NAME() \
			{ \
				return VARIABLE; \
			} \
			void GuiWindow::Set ## NAME(bool visible) \
			{ \
				auto ct = TypedControlTemplateObject(true); \
				if (ct->Get ## NAME ## Option() == BoolOption::Customizable) \
				{ \
					VARIABLE = visible; \
					ct->Set ## NAME(visible); \
					auto window = GetNativeWindow(); \
					if (window) \
					{ \
						CONDITION_BREAK \
						window->Set ## NAME(visible); \
					} \
					UpdateCustomFramePadding(window, ct); \
				} \
			} \

#define IMPL_WINDOW_PROPERTY_EMPTY_CONDITION
#define IMPL_WINDOW_PROPERTY_BORDER_CONDITION if (!ct->GetCustomFrameEnabled())

			IMPL_WINDOW_PROPERTY(hasMaximizedBox, MaximizedBox, IMPL_WINDOW_PROPERTY_EMPTY_CONDITION)
			IMPL_WINDOW_PROPERTY(hasMinimizedBox, MinimizedBox, IMPL_WINDOW_PROPERTY_EMPTY_CONDITION)
			IMPL_WINDOW_PROPERTY(hasBorder, Border, IMPL_WINDOW_PROPERTY_BORDER_CONDITION)
			IMPL_WINDOW_PROPERTY(hasSizeBox, SizeBox, IMPL_WINDOW_PROPERTY_EMPTY_CONDITION)
			IMPL_WINDOW_PROPERTY(isIconVisible, IconVisible, IMPL_WINDOW_PROPERTY_EMPTY_CONDITION)
			IMPL_WINDOW_PROPERTY(hasTitleBar, TitleBar, IMPL_WINDOW_PROPERTY_EMPTY_CONDITION)

			Ptr<GuiImageData> GuiWindow::GetIcon()
			{
				return icon;
			}

			void GuiWindow::SetIcon(Ptr<GuiImageData> value)
			{
				if (icon != value)
				{
					icon = value;

					auto window = GetNativeWindow();
					if (window)
					{
						window->SetIcon(icon);
					}

					if (auto ct = TypedControlTemplateObject(false))
					{
						UpdateIcon(window, ct);
					}
				}
			}

#undef IMPL_WINDOW_PROPERTY_BORDER_CONDITION
#undef IMPL_WINDOW_PROPERTY_EMPTY_CONDITION
#undef IMPL_WINDOW_PROPERTY

			void GuiWindow::ShowWithOwner(GuiWindow* owner)
			{
				auto ownerNativeWindow = owner->GetNativeWindow();
				auto nativeWindow = GetNativeWindow();
				auto previousParent = nativeWindow->GetParent();
				if (ownerNativeWindow != previousParent)
				{
					nativeWindow->SetParent(ownerNativeWindow);
					WindowReadyToClose.AttachLambda([=](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
					{
						nativeWindow->SetParent(previousParent);
					});
				}
				Show();
			}

			void GuiWindow::ShowModal(GuiWindow* owner, const Func<void()>& callback)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::GuiWindow::ShowModal(GuiWindow*, const Func<void()>&)#"
				CHECK_ERROR(!showModalRecord, ERROR_MESSAGE_PREFIX L"Cannot call this function nestedly.");
				CHECK_ERROR(owner && owner->GetEnabled(), ERROR_MESSAGE_PREFIX L"The owner should not have been disabled.");

				if (!owner->showModalRecord)
				{
					owner->showModalRecord = Ptr(new ShowModalRecord{ owner,owner });
				}

				showModalRecord = owner->showModalRecord;
				showModalRecord->current = this;
				owner->SetEnabled(false);
				GetNativeWindow()->SetParent(owner->GetNativeWindow());

				auto container = Ptr(new IGuiGraphicsEventHandler::Container);
				auto disposeFlag = GetDisposedFlag();
				container->handler = WindowReadyToClose.AttachLambda([=, this](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
				{
					callback();

					GetNativeWindow()->SetParent(nullptr);
					owner->SetEnabled(true);
					owner->SetFocused();
					showModalRecord = nullptr;
					owner->showModalRecord->current = owner;
					if (owner->showModalRecord->current == owner->showModalRecord->origin)
					{
						owner->showModalRecord = nullptr;
					}

					GetApplication()->InvokeInMainThread(this, [=, this]()
					{
						if (!disposeFlag->IsDisposed())
						{
							WindowReadyToClose.Detach(container->handler);
						}
						container->handler = nullptr;
					});
				});
				Show();
#undef ERROR_MESSAGE_PREFIX
			}

			void GuiWindow::ShowModalAndDelete(GuiWindow* owner, const Func<void()>& callback)
			{
				ShowModal(owner, [=, this]()
				{
					callback();
					DeleteAfterProcessingAllEvents({});
				});
			}

			void GuiWindow::ShowModalAndDelete(GuiWindow* owner, const Func<void()>& callbackClosed, const Func<void()>& callbackDeleted)
			{
				ShowModal(owner, [=, this]()
				{
					callbackClosed();
					DeleteAfterProcessingAllEvents(callbackDeleted);
				});
			}

			Ptr<reflection::description::IAsync> GuiWindow::ShowModalAsync(GuiWindow* owner)
			{
				auto future = IFuture::Create();
				ShowModal(owner, [promise = future->GetPromise()]()
				{
					promise->SendResult({});
				});
				return future;
			}

/***********************************************************************
GuiPopup
***********************************************************************/

			void GuiPopup::UpdateClientSizeAfterRendering(Size preferredSize, Size clientSize)
			{
				if (popupType == -1)
				{
					GuiWindow::UpdateClientSizeAfterRendering(preferredSize, clientSize);
				}
				else
				{
					auto window = host->GetNativeWindow();
					auto currentClientSize = window->GetClientSize();
					auto currentWindowSize = window->GetBounds().GetSize();
					auto offsetX = currentWindowSize.x - currentClientSize.x;
					auto offsetY = currentWindowSize.y - currentClientSize.y;
					auto nativeClientSize = window->Convert(clientSize);
					auto position = CalculatePopupPosition(NativeSize(nativeClientSize.x + offsetX, nativeClientSize.y + offsetY), popupType, popupInfo);
					if (position != GetLocation() || clientSize != GetClientSize())
					{
						SetBounds(position, clientSize);
					}
				}
			}

			void GuiPopup::PopupOpened(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				GetApplication()->RegisterPopupOpened(this);
			}

			void GuiPopup::PopupClosed(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				popupType = -1;
				GetApplication()->RegisterPopupClosed(this);
				if(auto window = GetNativeWindow())
				{
					window->SetParent(nullptr);
				}
			}

			void GuiPopup::OnKeyDown(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
				if (arguments.code == VKEY::KEY_ESCAPE && !arguments.ctrl && !arguments.shift && !arguments.alt)
				{
					Hide();
					arguments.handled = true;
				}
			}

			bool GuiPopup::IsClippedByScreen(NativeSize size, NativePoint location, INativeScreen* screen)
			{
				NativeRect screenBounds = screen->GetClientBounds();
				NativeRect windowBounds(location, size);
				return !screenBounds.Contains(windowBounds.LeftTop()) || !screenBounds.Contains(windowBounds.RightBottom());
			}

			NativePoint GuiPopup::CalculatePopupPosition(NativeSize windowSize, NativePoint location, INativeScreen* screen)
			{
				NativeRect screenBounds = screen->GetClientBounds();

				if (location.x < screenBounds.x1)
				{
					location.x = screenBounds.x1;
				}
				else if (location.x + windowSize.x > screenBounds.x2)
				{
					location.x = screenBounds.x2 - windowSize.x;
				}

				if (location.y < screenBounds.y1)
				{
					location.y = screenBounds.y1;
				}
				else if (location.y + windowSize.y > screenBounds.y2)
				{
					location.y = screenBounds.y2 - windowSize.y;
				}

				return location;
			}

			NativePoint GuiPopup::CalculatePopupPosition(NativeSize windowSize, GuiControl* control, INativeWindow* controlWindow, Rect bounds, bool preferredTopBottomSide)
			{
				NativePoint controlClientOffset = controlWindow->Convert(control->GetBoundsComposition()->GetGlobalBounds().LeftTop());
				NativePoint controlWindowOffset = controlWindow->GetClientBoundsInScreen().LeftTop();
				NativeRect targetBounds(controlWindow->Convert(bounds.LeftTop()), controlWindow->Convert(bounds.GetSize()));
				targetBounds.x1 += controlClientOffset.x + controlWindowOffset.x;
				targetBounds.x2 += controlClientOffset.x + controlWindowOffset.x;
				targetBounds.y1 += controlClientOffset.y + controlWindowOffset.y;
				targetBounds.y2 += controlClientOffset.y + controlWindowOffset.y;

				NativePoint locations[4];
				if (preferredTopBottomSide)
				{
					locations[0] = NativePoint(targetBounds.x1, targetBounds.y2);
					locations[1] = NativePoint(targetBounds.x2 - windowSize.x, targetBounds.y2);
					locations[2] = NativePoint(targetBounds.x1, targetBounds.y1 - windowSize.y);
					locations[3] = NativePoint(targetBounds.x2 - windowSize.x, targetBounds.y1 - windowSize.y);
				}
				else
				{
					locations[0] = NativePoint(targetBounds.x2, targetBounds.y1);
					locations[1] = NativePoint(targetBounds.x2, targetBounds.y2 - windowSize.y);
					locations[2] = NativePoint(targetBounds.x1 - windowSize.x, targetBounds.y1);
					locations[3] = NativePoint(targetBounds.x1 - windowSize.x, targetBounds.y2 - windowSize.y);
				}

				auto screen = GetCurrentController()->ScreenService()->GetScreen(controlWindow);
				for (vint i = 0; i < 4; i++)
				{
					if (!IsClippedByScreen(windowSize, locations[i], screen))
					{
						return CalculatePopupPosition(windowSize, locations[i], screen);
					}
				}
				return CalculatePopupPosition(windowSize, locations[0], screen);
			}

			NativePoint GuiPopup::CalculatePopupPosition(NativeSize windowSize, GuiControl* control, INativeWindow* controlWindow, Point location)
			{
				NativePoint controlClientOffset = controlWindow->Convert(control->GetBoundsComposition()->GetGlobalBounds().LeftTop());
				NativePoint controlWindowOffset = controlWindow->GetClientBoundsInScreen().LeftTop();
				NativePoint targetLocation = controlWindow->Convert(location);
				NativeCoordinate x = controlClientOffset.x + controlWindowOffset.x + targetLocation.x;
				NativeCoordinate y = controlClientOffset.y + controlWindowOffset.y + targetLocation.y;
				return CalculatePopupPosition(windowSize, NativePoint(x, y), GetCurrentController()->ScreenService()->GetScreen(controlWindow));
			}

			NativePoint GuiPopup::CalculatePopupPosition(NativeSize windowSize, GuiControl* control, INativeWindow* controlWindow, bool preferredTopBottomSide)
			{
				Rect bounds(Point(0, 0), control->GetBoundsComposition()->GetCachedBounds().GetSize());
				return CalculatePopupPosition(windowSize, control, controlWindow, bounds, preferredTopBottomSide);
			}

			NativePoint GuiPopup::CalculatePopupPosition(NativeSize windowSize, vint popupType, const PopupInfo& popupInfo)
			{
				switch (popupType)
				{
				case 1:
					return CalculatePopupPosition(windowSize, popupInfo._1.location, popupInfo._1.screen);
				case 2:
					return CalculatePopupPosition(windowSize, popupInfo._2.control, popupInfo._2.controlWindow, popupInfo._2.bounds, popupInfo._2.preferredTopBottomSide);
				case 3:
					return CalculatePopupPosition(windowSize, popupInfo._3.control, popupInfo._3.controlWindow, popupInfo._3.location);
				case 4:
					return CalculatePopupPosition(windowSize, popupInfo._4.control, popupInfo._4.controlWindow, popupInfo._4.preferredTopBottomSide);
				default:
					CHECK_FAIL(L"vl::presentation::controls::GuiPopup::CalculatePopupPosition(Size, const PopupInfo&)#Internal error.");
				}
			}

			void GuiPopup::ShowPopupInternal()
			{
				auto window = GetNativeWindow();
				auto clientSize = window->Convert(window->GetClientSize());
				UpdateClientSizeAfterRendering(clientSize, clientSize);

				INativeWindow* controlWindow = nullptr;
				switch (popupType)
				{
				case 2: controlWindow = popupInfo._2.controlWindow; break;
				case 3: controlWindow = popupInfo._3.controlWindow; break;
				case 4: controlWindow = popupInfo._4.controlWindow; break;
				}

				if (controlWindow)
				{
					window->SetParent(controlWindow);
					SetTopMost(controlWindow->GetTopMost());
				}
				else
				{
					SetTopMost(true);
				}
				SetEnabledActivate(false);
				ShowDeactivated();
			}

			GuiPopup::GuiPopup(theme::ThemeName themeName, INativeWindow::WindowMode mode)
				:GuiWindow(themeName, mode)
			{
				SetMinimizedBox(false);
				SetMaximizedBox(false);
				SetBorder(false);
				SetSizeBox(false);
				SetIconVisible(false);
				SetTitleBar(false);
				SetShowInTaskBar(false);

				WindowOpened.AttachMethod(this, &GuiPopup::PopupOpened);
				WindowClosed.AttachMethod(this, &GuiPopup::PopupClosed);
				boundsComposition->GetEventReceiver()->keyDown.AttachMethod(this, &GuiPopup::OnKeyDown);
			}

			GuiPopup::GuiPopup(theme::ThemeName themeName)
				:GuiPopup(themeName, INativeWindow::Popup)
			{
			}

			GuiPopup::~GuiPopup()
			{
				GetApplication()->RegisterPopupClosed(this);
			}

			void GuiPopup::ShowPopup(NativePoint location, INativeScreen* screen)
			{
				if (auto window = GetNativeWindow())
				{
					if (!screen)
					{
						SetBounds(location, GetClientSize());
						screen = GetCurrentController()->ScreenService()->GetScreen(window);
					}

					popupType = 1;
					popupInfo._1.location = location;
					popupInfo._1.screen = screen;
					ShowPopupInternal();
				}
			}
			
			void GuiPopup::ShowPopup(GuiControl* control, Rect bounds, bool preferredTopBottomSide)
			{
				if (auto window = GetNativeWindow())
				{
					if (auto controlHost = control->GetBoundsComposition()->GetRelatedControlHost())
					{
						if (auto controlWindow = controlHost->GetNativeWindow())
						{
							popupType = 2;
							popupInfo._2.control = control;
							popupInfo._2.controlWindow = controlWindow;
							popupInfo._2.bounds = bounds;
							popupInfo._2.preferredTopBottomSide = preferredTopBottomSide;
							ShowPopupInternal();
						}
					}
				}
			}

			void GuiPopup::ShowPopup(GuiControl* control, Point location)
			{
				if (auto window = GetNativeWindow())
				{
					if (auto controlHost = control->GetBoundsComposition()->GetRelatedControlHost())
					{
						if (auto controlWindow = controlHost->GetNativeWindow())
						{
							popupType = 3;
							popupInfo._3.control = control;
							popupInfo._3.controlWindow = controlWindow;
							popupInfo._3.location = location;
							ShowPopupInternal();
						}
					}
				}
			}

			void GuiPopup::ShowPopup(GuiControl* control, bool preferredTopBottomSide)
			{
				if (auto window = GetNativeWindow())
				{
					if (auto controlHost = control->GetBoundsComposition()->GetRelatedControlHost())
					{
						if (auto controlWindow = controlHost->GetNativeWindow())
						{
							popupType = 4;
							popupInfo._4.control = control;
							popupInfo._4.controlWindow = controlWindow;
							popupInfo._4.preferredTopBottomSide = preferredTopBottomSide;
							ShowPopupInternal();
						}
					}
				}
			}

/***********************************************************************
GuiPopup
***********************************************************************/

			void GuiTooltip::GlobalTimer()
			{
				SetClientSize(GetClientSize());
			}

			void GuiTooltip::TooltipOpened(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
			}

			void GuiTooltip::TooltipClosed(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				SetTemporaryContentControl(0);
			}

			GuiTooltip::GuiTooltip(theme::ThemeName themeName)
				: GuiPopup(themeName, INativeWindow::Tooltip)
			{
				containerComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				containerComposition->SetPreferredMinSize(Size(20, 10));
				GetCurrentController()->CallbackService()->InstallListener(this);

				WindowOpened.AttachMethod(this, &GuiTooltip::TooltipOpened);
				WindowClosed.AttachMethod(this, &GuiTooltip::TooltipClosed);
			}

			GuiTooltip::~GuiTooltip()
			{
				GetCurrentController()->CallbackService()->UninstallListener(this);
			}

			vint GuiTooltip::GetPreferredContentWidth()
			{
				return containerComposition->GetPreferredMinSize().x;
			}

			void GuiTooltip::SetPreferredContentWidth(vint value)
			{
				containerComposition->SetPreferredMinSize(Size(value, 10));
			}

			GuiControl* GuiTooltip::GetTemporaryContentControl()
			{
				return temporaryContentControl;
			}

			void GuiTooltip::SetTemporaryContentControl(GuiControl* control)
			{
				if(temporaryContentControl && HasChild(temporaryContentControl))
				{
					containerComposition->RemoveChild(temporaryContentControl->GetBoundsComposition());
					temporaryContentControl=0;
				}
				temporaryContentControl=control;
				if(control)
				{
					control->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
					AddChild(control);
				}
			}
		}
	}
}


/***********************************************************************
.\APPLICATION\GRAPHICSCOMPOSITIONS\GUIGRAPHICSBOUNDSCOMPOSITION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace collections;
			using namespace elements;

/***********************************************************************
GuiBoundsComposition
***********************************************************************/

			Size GuiBoundsComposition::Layout_CalculateMinSize()
			{
				Size minSize = Layout_CalculateMinSizeHelper();
				if (minSize.x < expectedBounds.Width()) minSize.x = expectedBounds.Width();
				if (minSize.y < expectedBounds.Height()) minSize.y = expectedBounds.Height();
				return minSize;
			}

			Size GuiBoundsComposition::Layout_CalculateMinClientSizeForParent(Margin parentInternalMargin)
			{
				vint offsetW = 0;
				vint offsetH = 0;

				if (alignmentToParent.left == -1 && alignmentToParent.right == -1)
				{
					offsetW = expectedBounds.x1;
				}
				else
				{
					if (alignmentToParent.left != -1)
					{
						offsetW += alignmentToParent.left - parentInternalMargin.left;
					}
					if (alignmentToParent.right != -1)
					{
						offsetW += alignmentToParent.right - parentInternalMargin.right;
					}
				}

				if (alignmentToParent.top == -1 && alignmentToParent.bottom == -1)
				{
					offsetH = expectedBounds.y1;
				}
				else
				{
					if (alignmentToParent.top != -1)
					{
						offsetH += alignmentToParent.top - parentInternalMargin.top;
					}
					if (alignmentToParent.bottom != -1)
					{
						offsetH += alignmentToParent.bottom - parentInternalMargin.bottom;
					}
				}

				return { cachedMinSize.x + offsetW,cachedMinSize.y + offsetH };
			}

			Rect GuiBoundsComposition::Layout_CalculateBounds(Size parentSize)
			{
				if (auto parent = GetParent())
				{
					Rect result;
					Rect parentBounds({}, parentSize);
					Margin parentInternalMargin = parent->GetInternalMargin();

					if (alignmentToParent.left != -1 && alignmentToParent.right != -1)
					{
						result.x1 = parentBounds.x1 + alignmentToParent.left;
						result.x2 = parentBounds.x2 - alignmentToParent.right;
					}
					else if (alignmentToParent.left != -1)
					{
						result.x1 = parentBounds.x1 + alignmentToParent.left;
						result.x2 = result.x1 + cachedMinSize.x;
					}
					else if (alignmentToParent.right != -1)
					{
						result.x2 = parentBounds.x2 - alignmentToParent.right;
						result.x1 = result.x2 - cachedMinSize.x;
					}
					else
					{
						result.x1 = expectedBounds.x1 + parentInternalMargin.left;
						result.x2 = result.x1 + cachedMinSize.x;
					}

					if (alignmentToParent.top != -1 && alignmentToParent.bottom != -1)
					{
						result.y1 = parentBounds.y1 + alignmentToParent.top;
						result.y2 = parentBounds.y2 - alignmentToParent.bottom;
					}
					else if (alignmentToParent.top != -1)
					{
						result.y1 = parentBounds.y1 + alignmentToParent.top;
						result.y2 = result.y1 + cachedMinSize.y;
					}
					else if (alignmentToParent.bottom != -1)
					{
						result.y2 = parentBounds.y2 - alignmentToParent.bottom;
						result.y1 = result.y2 - cachedMinSize.y;
					}
					else
					{
						result.y1 = expectedBounds.y1 + parentInternalMargin.top;
						result.y2 = result.y1 + cachedMinSize.y;
					}

					return result;
				}
				else
				{
					return Rect(expectedBounds.LeftTop(), cachedMinSize);
				}
			}

			Rect GuiBoundsComposition::GetExpectedBounds()
			{
				return expectedBounds;
			}

			void GuiBoundsComposition::SetExpectedBounds(Rect value)
			{
				if (value.x2 < value.x1) value.x2 = value.x1;
				if (value.y2 < value.y1) value.y2 = value.y1;

				if (expectedBounds != value)
				{
					expectedBounds = value;
					InvokeOnCompositionStateChanged();
				}
			}

			Margin GuiBoundsComposition::GetAlignmentToParent()
			{
				return alignmentToParent;
			}

			void GuiBoundsComposition::SetAlignmentToParent(Margin value)
			{
				if (alignmentToParent != value)
				{
					alignmentToParent = value;
					InvokeOnCompositionStateChanged();
				}
			}

			bool GuiBoundsComposition::IsAlignedToParent()
			{
				return alignmentToParent != Margin(-1, -1, -1, -1);
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\GRAPHICSCOMPOSITIONS\GUIGRAPHICSCOMPOSITION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace elements;

			void InvokeOnCompositionStateChanged(compositions::GuiGraphicsComposition* composition)
			{
				composition->InvokeOnCompositionStateChanged();
			}

/***********************************************************************
GuiGraphicsComposition
***********************************************************************/

			void GuiGraphicsComposition::OnControlParentChanged(controls::GuiControl* control)
			{
				if (associatedControl && associatedControl != control)
				{
					if (associatedControl->GetParent())
					{
						associatedControl->GetParent()->OnChildRemoved(associatedControl);
					}
					if (control)
					{
						control->OnChildInserted(associatedControl);
					}
				}
				else
				{
					for (auto child : children)
					{
						child->OnControlParentChanged(control);
					}
				}
			}

			void GuiGraphicsComposition::OnChildInserted(GuiGraphicsComposition* child)
			{
				child->OnControlParentChanged(GetRelatedControl());
			}

			void GuiGraphicsComposition::OnChildRemoved(GuiGraphicsComposition* child)
			{
				child->OnControlParentChanged(nullptr);
			}

			void GuiGraphicsComposition::OnParentChanged(GuiGraphicsComposition* oldParent, GuiGraphicsComposition* newParent)
			{
				OnParentLineChanged();
			}

			void GuiGraphicsComposition::OnParentLineChanged()
			{
				for (auto child : children)
				{
					child->OnParentLineChanged();
				}
			}

			void GuiGraphicsComposition::OnCompositionStateChanged()
			{
			}

			void GuiGraphicsComposition::OnRenderContextChanged()
			{
			}

			void GuiGraphicsComposition::UpdateRelatedHostRecord(GraphicsHostRecord* record)
			{
				relatedHostRecord = record;
				auto renderTarget = GetRenderTarget();

				if (ownedElement)
				{
					if (auto renderer = ownedElement->GetRenderer())
					{
						renderer->SetRenderTarget(renderTarget);
					}
				}

				for (auto child : children)
				{
					child->UpdateRelatedHostRecord(record);
				}

				if (HasEventReceiver())
				{
					GetEventReceiver()->renderTargetChanged.Execute(GuiEventArgs(this));
				}
				if (associatedControl)
				{
					associatedControl->OnRenderTargetChanged(renderTarget);
				}

				OnRenderContextChanged();
			}

			void GuiGraphicsComposition::SetAssociatedControl(controls::GuiControl* control)
			{
				if (associatedControl)
				{
					for (auto child : children)
					{
						child->OnControlParentChanged(nullptr);
					}
				}
				associatedControl = control;
				if (associatedControl)
				{
					for (auto child : children)
					{
						child->OnControlParentChanged(associatedControl);
					}
				}
			}

			void GuiGraphicsComposition::InvokeOnCompositionStateChanged(bool forceRequestRender)
			{
				OnCompositionStateChanged();
				if (relatedHostRecord && (forceRequestRender || GetEventuallyVisible()))
				{
					relatedHostRecord->host->RequestRender();
				}
			}

			bool GuiGraphicsComposition::SharedPtrDestructorProc(DescriptableObject* obj, bool forceDisposing)
			{
				GuiGraphicsComposition* value=dynamic_cast<GuiGraphicsComposition*>(obj);
				if(value->parent)
				{
					if (!forceDisposing) return false;
				}
				SafeDeleteComposition(value);
				return true;
			}

			GuiGraphicsComposition::GuiGraphicsComposition()
			{
				sharedPtrDestructorProc = &GuiGraphicsComposition::SharedPtrDestructorProc;
				CachedMinSizeChanged.SetAssociatedComposition(this);
				CachedBoundsChanged.SetAssociatedComposition(this);
			}

			GuiGraphicsComposition::~GuiGraphicsComposition()
			{
				for (auto child : children)
				{
					delete child;
				}
			}

			bool GuiGraphicsComposition::IsRendering()
			{
				return isRendering;
			}

			GuiGraphicsComposition* GuiGraphicsComposition::GetParent()
			{
				return parent;
			}

			const GuiGraphicsComposition::CompositionList& GuiGraphicsComposition::Children()
			{
				return children;
			}

			bool GuiGraphicsComposition::AddChild(GuiGraphicsComposition* child)
			{
				return InsertChild(children.Count(), child);
			}

			bool GuiGraphicsComposition::InsertChild(vint index, GuiGraphicsComposition* child)
			{
				CHECK_ERROR(!isRendering, L"GuiGraphicsComposition::InsertChild(vint, GuiGraphicsComposition*)#Cannot modify composition tree during rendering.");
				if (!child) return false;
				if (child->GetParent()) return false;
				children.Insert(index, child);

				// composition parent changed -> control parent changed -> related host changed
				child->parent = this;
				child->OnParentChanged(nullptr, this);
				OnChildInserted(child);
				child->UpdateRelatedHostRecord(relatedHostRecord);

				InvokeOnCompositionStateChanged();
				return true;
			}

			bool GuiGraphicsComposition::RemoveChild(GuiGraphicsComposition* child)
			{
				CHECK_ERROR(!isRendering, L"GuiGraphicsComposition::InsertChild(vint, GuiGraphicsComposition*)#Cannot modify composition tree during rendering.");
				if (!child) return false;
				vint index = children.IndexOf(child);
				if (index == -1) return false;

				// composition parent changed -> control parent changed -> related host changed
				child->parent = nullptr;
				child->OnParentChanged(this, nullptr);
				OnChildRemoved(child);
				child->UpdateRelatedHostRecord(nullptr);

				GuiGraphicsHost* host = GetRelatedGraphicsHost();
				if (host)
				{
					host->DisconnectComposition(child);
				}
				children.RemoveAt(index);
				InvokeOnCompositionStateChanged();
				return true;
			}

			bool GuiGraphicsComposition::MoveChild(GuiGraphicsComposition* child, vint newIndex)
			{
				if(!child) return false;
				vint index=children.IndexOf(child);
				if(index==-1) return false;
				if(index==newIndex) return true;
				children.RemoveAt(index);
				children.Insert(newIndex, child);
				InvokeOnCompositionStateChanged();
				return true;
			}

			Ptr<IGuiGraphicsElement> GuiGraphicsComposition::GetOwnedElement()
			{
				return ownedElement;
			}

			void GuiGraphicsComposition::SetOwnedElement(Ptr<IGuiGraphicsElement> element)
			{
				if (ownedElement != element)
				{
					if (ownedElement)
					{
						if (auto renderer = ownedElement->GetRenderer())
						{
							renderer->SetRenderTarget(nullptr);
						}
						ownedElement->SetOwnerComposition(nullptr);
					}
					ownedElement = element;
					if (ownedElement)
					{
						if (auto renderer = ownedElement->GetRenderer())
						{
							renderer->SetRenderTarget(GetRenderTarget());
						}
						ownedElement->SetOwnerComposition(this);
					}
					InvokeOnCompositionStateChanged();
				}
			}

			bool GuiGraphicsComposition::GetVisible()
			{
				return visible;
			}

			void GuiGraphicsComposition::SetVisible(bool value)
			{
				if (visible != value)
				{
					visible = value;
					InvokeOnCompositionStateChanged(true);
				}
			}

			bool GuiGraphicsComposition::GetEventuallyVisible()
			{
				auto current = this;
				while (current)
				{
					if (!current->visible) return false;
					current = current->parent;
				}
				return true;
			}

			GuiGraphicsComposition::MinSizeLimitation GuiGraphicsComposition::GetMinSizeLimitation()
			{
				return minSizeLimitation;
			}

			void GuiGraphicsComposition::SetMinSizeLimitation(MinSizeLimitation value)
			{
				if (minSizeLimitation != value)
				{
					minSizeLimitation = value;
					InvokeOnCompositionStateChanged();
				}
			}

			elements::IGuiGraphicsRenderTarget* GuiGraphicsComposition::GetRenderTarget()
			{
				return relatedHostRecord ? relatedHostRecord->renderTarget : nullptr;
			}

			void GuiGraphicsComposition::Render(Size offset)
			{
				auto renderTarget = GetRenderTarget();
				if (visible && renderTarget && !renderTarget->IsClipperCoverWholeTarget())
				{
					Rect bounds = GetCachedBounds();
					if (bounds.x1 <= bounds.x2 && bounds.y1 <= bounds.y2)
					{
						bounds.x1 += offset.x;
						bounds.x2 += offset.x;
						bounds.y1 += offset.y;
						bounds.y2 += offset.y;

						isRendering = true;
						if (ownedElement)
						{
							IGuiGraphicsRenderer* renderer = ownedElement->GetRenderer();
							if (renderer)
							{
								renderer->Render(bounds);
							}
						}

						if (children.Count() > 0 || associatedHitTestResult != INativeWindowListener::NoDecision || associatedCursor)
						{
							renderTarget->PushClipper(bounds, this);
							if (!renderTarget->IsClipperCoverWholeTarget())
							{
								for (auto child : children)
								{
									child->Render(Size(bounds.x1, bounds.y1));
								}
							}
							renderTarget->PopClipper(this);
						}
						isRendering = false;
					}
				}
			}

			GuiGraphicsEventReceiver* GuiGraphicsComposition::GetEventReceiver()
			{
				if(!eventReceiver)
				{
					eventReceiver=Ptr(new GuiGraphicsEventReceiver(this));
				}
				return eventReceiver.Obj();
			}

			bool GuiGraphicsComposition::HasEventReceiver()
			{
				return eventReceiver;
			}

			GuiGraphicsComposition* GuiGraphicsComposition::FindVisibleComposition(Point location, bool forMouseEvent)
			{
				if (!visible) return 0;
				Rect bounds = GetCachedBounds();
				Rect relativeBounds = Rect(Point(0, 0), bounds.GetSize());
				if (relativeBounds.Contains(location))
				{
					// TODO: (enumerable) foreach:reversed
					for (vint i = children.Count() - 1; i >= 0; i--)
					{
						GuiGraphicsComposition* child = children[i];
						Rect childBounds = child->GetCachedBounds();
						Point newLocation = location - Size(childBounds.x1, childBounds.y1);
						GuiGraphicsComposition* childResult = child->FindVisibleComposition(newLocation, forMouseEvent);
						if (childResult)
						{
							return childResult;
						}
					}

					if (!forMouseEvent || !transparentToMouse)
					{
						return this;
					}
				}
				return nullptr;
			}

			bool GuiGraphicsComposition::GetTransparentToMouse()
			{
				return transparentToMouse;
			}

			void GuiGraphicsComposition::SetTransparentToMouse(bool value)
			{
				transparentToMouse = value;
			}

			controls::GuiControl* GuiGraphicsComposition::GetAssociatedControl()
			{
				return associatedControl;
			}

			GuiGraphicsHost* GuiGraphicsComposition::GetAssociatedHost()
			{
				if (relatedHostRecord && relatedHostRecord->host->GetMainComposition() == this)
				{
					return relatedHostRecord->host;
				}
				else
				{
					return nullptr;
				}
			}

			INativeCursor* GuiGraphicsComposition::GetAssociatedCursor()
			{
				return associatedCursor;
			}

			void GuiGraphicsComposition::SetAssociatedCursor(INativeCursor* cursor)
			{
				associatedCursor = cursor;
			}

			INativeWindowListener::HitTestResult GuiGraphicsComposition::GetAssociatedHitTestResult()
			{
				return associatedHitTestResult;
			}

			void GuiGraphicsComposition::SetAssociatedHitTestResult(INativeWindowListener::HitTestResult value)
			{
				associatedHitTestResult = value;
			}

			controls::GuiControl* GuiGraphicsComposition::GetRelatedControl()
			{
				GuiGraphicsComposition* composition = this;
				while (composition)
				{
					if (composition->GetAssociatedControl())
					{
						return composition->GetAssociatedControl();
					}
					else
					{
						composition = composition->GetParent();
					}
				}
				return nullptr;
			}

			GuiGraphicsHost* GuiGraphicsComposition::GetRelatedGraphicsHost()
			{
				return relatedHostRecord ? relatedHostRecord->host : nullptr;
			}

			controls::GuiControlHost* GuiGraphicsComposition::GetRelatedControlHost()
			{
				if (auto control = GetRelatedControl())
				{
					return control->GetRelatedControlHost();
				}
				return nullptr;
			}

			INativeCursor* GuiGraphicsComposition::GetRelatedCursor()
			{
				GuiGraphicsComposition* composition = this;
				while (composition)
				{
					if (composition->GetAssociatedCursor())
					{
						return composition->GetAssociatedCursor();
					}
					else
					{
						composition = composition->GetParent();
					}
				}
				return nullptr;
			}

			INativeWindowListener::HitTestResult GuiGraphicsComposition::GetRelatedHitTestResult()
			{
				GuiGraphicsComposition* composition = this;
				while (composition)
				{
					INativeWindowListener::HitTestResult result = composition->GetAssociatedHitTestResult();
					if (result == INativeWindowListener::NoDecision)
					{
						composition = composition->GetParent();
					}
					else
					{
						return result;
					}
				}
				return INativeWindowListener::NoDecision;
			}

			Margin GuiGraphicsComposition::GetInternalMargin()
			{
				return internalMargin;
			}

			void GuiGraphicsComposition::SetInternalMargin(Margin value)
			{
				if (value.left < 0) value.left = 0;
				if (value.top < 0) value.top = 0;
				if (value.right < 0) value.right = 0;
				if (value.bottom < 0) value.bottom = 0;

				if (internalMargin != value)
				{
					internalMargin = value;
					InvokeOnCompositionStateChanged();
				}
			}

			Size GuiGraphicsComposition::GetPreferredMinSize()
			{
				return preferredMinSize;
			}

			void GuiGraphicsComposition::SetPreferredMinSize(Size value)
			{
				if (value.x < 0) value.x = 0;
				if (value.y < 0) value.y = 0;

				if (preferredMinSize != value)
				{
					preferredMinSize = value;
					InvokeOnCompositionStateChanged();
				}
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\GRAPHICSCOMPOSITIONS\GUIGRAPHICSCOMPOSITION_HELPERS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace controls;

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

			void NotifyFinalizeInstance(controls::GuiControl* value)
			{
				if (value)
				{
					NotifyFinalizeInstance(value->GetBoundsComposition());
				}
			}

			void NotifyFinalizeInstance(GuiGraphicsComposition* value)
			{
				if (value)
				{
					bool finalized = false;
					if (auto root = dynamic_cast<GuiInstanceRootObject*>(value))
					{
						if (root->IsFinalized())
						{
							finalized = true;
						}
						else
						{
							root->FinalizeInstance();
						}
					}

					if (auto control = value->GetAssociatedControl())
					{
						if (auto root = dynamic_cast<GuiInstanceRootObject*>(control))
						{
							if (root->IsFinalized())
							{
								finalized = true;
							}
							else
							{
								root->FinalizeInstance();
							}
						}
					}

					if (!finalized)
					{
						for (auto child : value->Children())
						{
							NotifyFinalizeInstance(child);
						}
					}
				}
			}

			void SafeDeleteControlInternal(controls::GuiControl* value)
			{
				if(value)
				{
					if (value->GetRelatedControlHost() != value)
					{
						GuiGraphicsComposition* bounds = value->GetBoundsComposition();
						if (bounds->GetParent())
						{
							bounds->GetParent()->RemoveChild(bounds);
						}
					}
					delete value;
				}
			}

			void SafeDeleteCompositionInternal(GuiGraphicsComposition* value)
			{
				if (value)
				{
					if (value->GetParent())
					{
						value->GetParent()->RemoveChild(value);
					}

					if (value->GetAssociatedControl())
					{
						SafeDeleteControlInternal(value->GetAssociatedControl());
					}
					else
					{
						// TODO: (enumerable) foreach:reversed
						for (vint i = value->Children().Count() - 1; i >= 0; i--)
						{
							SafeDeleteCompositionInternal(value->Children().Get(i));
						}
						delete value;
					}
				}
			}

			void SafeDeleteControl(controls::GuiControl* value)
			{
				if (auto controlHost = dynamic_cast<controls::GuiControlHost*>(value))
				{
					controlHost->DeleteAfterProcessingAllEvents({});
				}
				else
				{
					NotifyFinalizeInstance(value);
					SafeDeleteControlInternal(value);
				}
			}

			void SafeDeleteComposition(GuiGraphicsComposition* value)
			{
				NotifyFinalizeInstance(value);
				SafeDeleteCompositionInternal(value);
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\GRAPHICSCOMPOSITIONS\GUIGRAPHICSCOMPOSITION_LAYOUT.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace elements;

/***********************************************************************
GuiGraphicsComposition
***********************************************************************/

			Size GuiGraphicsComposition::Layout_CalculateMinSizeHelper()
			{
				Size minSize;
				if (minSize.x < preferredMinSize.x) minSize.x = preferredMinSize.x;
				if (minSize.y < preferredMinSize.y) minSize.y = preferredMinSize.y;

				if (minSizeLimitation != GuiGraphicsComposition::NoLimit)
				{
					if (ownedElement)
					{
						IGuiGraphicsRenderer* renderer = ownedElement->GetRenderer();
						if (renderer)
						{
							auto elementSize = renderer->GetMinSize();
							if (minSize.x < elementSize.x) minSize.x = elementSize.x;
							if (minSize.y < elementSize.y) minSize.y = elementSize.y;
						}
					}
				}

				vint offsetW = internalMargin.left + internalMargin.right;
				vint offsetH = internalMargin.top + internalMargin.bottom;
				minSize.x += offsetW;
				minSize.y += offsetH;

				for (auto child : children)
				{
					child->Layout_UpdateMinSize();
				}

				if (minSizeLimitation == GuiGraphicsComposition::LimitToElementAndChildren)
				{
					for (auto child : children)
					{
						Size minClientSize = child->Layout_CalculateMinClientSizeForParent(internalMargin);
						Size minBoundsSize(minClientSize.x + offsetW, minClientSize.y + offsetH);
						if (minSize.x < minBoundsSize.x) minSize.x = minBoundsSize.x;
						if (minSize.y < minBoundsSize.y) minSize.y = minBoundsSize.y;
					}
				}
				return minSize;
			}

			void GuiGraphicsComposition::Layout_SetCachedMinSize(Size value)
			{
				if (value.x < 0) value.x = 0;
				if (value.y < 0) value.y = 0;

				if (cachedMinSize != value)
				{
					cachedMinSize = value;
					CachedMinSizeChanged.Execute(GuiEventArgs(this));
					InvokeOnCompositionStateChanged();
				}
			}

			void GuiGraphicsComposition::Layout_SetCachedBounds(Rect value)
			{
				if (value.x2 < value.x1) value.x2 = value.x1;
				if (value.y2 < value.y1) value.y2 = value.y1;

				if (cachedBounds != value)
				{
					cachedBounds = value;
					CachedBoundsChanged.Execute(GuiEventArgs(this));
					InvokeOnCompositionStateChanged();
				}
			}

			void GuiGraphicsComposition::Layout_UpdateMinSize()
			{
				Layout_SetCachedMinSize(Layout_CalculateMinSize());
			}

			void GuiGraphicsComposition::Layout_UpdateBounds(Size parentSize)
			{
				Layout_SetCachedBounds(Layout_CalculateBounds(parentSize));
				for (auto child : children)
				{
					child->Layout_UpdateBounds(cachedBounds.GetSize());
				}
			}

			Size GuiGraphicsComposition::GetCachedMinSize()
			{
				return cachedMinSize;
			}

			Size GuiGraphicsComposition::GetCachedMinClientSize()
			{
				auto minSize = cachedMinSize;
				minSize.x -= internalMargin.left + internalMargin.right;
				minSize.y -= internalMargin.top + internalMargin.bottom;
				return minSize;
			}

			Rect GuiGraphicsComposition::GetCachedBounds()
			{
				return cachedBounds;
			}

			Rect GuiGraphicsComposition::GetCachedClientArea()
			{
				Rect bounds = cachedBounds;
				bounds.x1 += internalMargin.left;
				bounds.y1 += internalMargin.top;
				bounds.x2 -= internalMargin.right;
				bounds.y2 -= internalMargin.bottom;
				if (bounds.x2 < bounds.x1) bounds.x2 = bounds.x1;
				if (bounds.y2 < bounds.y1) bounds.y2 = bounds.y1;
				return bounds;
			}

			Rect GuiGraphicsComposition::GetGlobalBounds()
			{
				Rect bounds = cachedBounds;
				GuiGraphicsComposition* composition = parent;
				while (composition)
				{
					Point offset = composition->cachedBounds.LeftTop();
					bounds.x1 += offset.x;
					bounds.x2 += offset.x;
					bounds.y1 += offset.y;
					bounds.y2 += offset.y;
					composition = composition->parent;
				}
				return bounds;
			}

			void GuiGraphicsComposition::ForceCalculateSizeImmediately()
			{
				Size parentSize;
				if (parent)
				{
					parentSize = parent->cachedBounds.GetSize();
				}

				Layout_UpdateMinSize();
				Layout_UpdateBounds(parentSize);
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\GRAPHICSCOMPOSITIONS\GUIGRAPHICSEVENTRECEIVER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{

/***********************************************************************
Event Receiver
***********************************************************************/

			GuiGraphicsEventReceiver::GuiGraphicsEventReceiver(GuiGraphicsComposition* _sender)
				:sender(_sender)
				,leftButtonDown(_sender)
				,leftButtonUp(_sender)
				,leftButtonDoubleClick(_sender)
				,middleButtonDown(_sender)
				,middleButtonUp(_sender)
				,middleButtonDoubleClick(_sender)
				,rightButtonDown(_sender)
				,rightButtonUp(_sender)
				,rightButtonDoubleClick(_sender)
				,horizontalWheel(_sender)
				,verticalWheel(_sender)
				,mouseMove(_sender)
				,mouseEnter(_sender)
				,mouseLeave(_sender)
				,previewKey(_sender)
				,keyDown(_sender)
				,keyUp(_sender)
				,previewCharInput(_sender)
				,charInput(_sender)
				,gotFocus(_sender)
				,lostFocus(_sender)
				,caretNotify(_sender)
				,clipboardNotify(_sender)
				,renderTargetChanged(_sender)
			{
			}

			GuiGraphicsEventReceiver::~GuiGraphicsEventReceiver()
			{
			}

			GuiGraphicsComposition* GuiGraphicsEventReceiver::GetAssociatedComposition()
			{
				return sender;
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\GRAPHICSCOMPOSITIONS\GUIGRAPHICSWINDOWCOMPOSITION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{

/***********************************************************************
GuiWindowComposition
***********************************************************************/

			Rect GuiWindowComposition::Layout_CalculateBounds(Size parentSize)
			{
				Rect bounds;
				if (relatedHostRecord)
				{
					if (auto window = relatedHostRecord->host->GetNativeWindow())
					{
						bounds = Rect(Point(0, 0), window->Convert(window->GetClientSize()));
					}
				}
				return bounds;
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\GRAPHICSHOST\GUIGRAPHICSHOST.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace collections;
			using namespace controls;
			using namespace elements;

/***********************************************************************
GuiGraphicsTimerManager
***********************************************************************/

			GuiGraphicsTimerManager::GuiGraphicsTimerManager()
			{
			}

			GuiGraphicsTimerManager::~GuiGraphicsTimerManager()
			{
			}

			void GuiGraphicsTimerManager::AddCallback(Ptr<IGuiGraphicsTimerCallback> callback)
			{
				callbacks.Add(callback);
			}

			void GuiGraphicsTimerManager::Play()
			{
				// TODO: (enumerable) foreach:indexed(alterable(reversed))
				for (vint i = callbacks.Count() - 1; i >= 0; i--)
				{
					auto callback = callbacks[i];
					if (!callback->Play())
					{
						callbacks.RemoveAt(i);
					}
				}
			}

/***********************************************************************
GuiGraphicsHost
***********************************************************************/

			void GuiGraphicsHost::RefreshRelatedHostRecord(INativeWindow* nativeWindow)
			{
				hostRecord.nativeWindow = nativeWindow;
				hostRecord.renderTarget = nativeWindow ? GetGuiGraphicsResourceManager()->GetRenderTarget(nativeWindow) : nullptr;
				windowComposition->UpdateRelatedHostRecord(&hostRecord);
			}

			void GuiGraphicsHost::SetFocusInternal(GuiGraphicsComposition* composition)
			{
				if (focusedComposition && focusedComposition->HasEventReceiver())
				{
					GuiEventArgs arguments;
					arguments.compositionSource = focusedComposition;
					arguments.eventSource = focusedComposition;
					focusedComposition->GetEventReceiver()->lostFocus.Execute(arguments);
				}
				focusedComposition = composition;
				SetCaretPoint(Point(0, 0));
				if (focusedComposition && focusedComposition->HasEventReceiver())
				{
					GuiEventArgs arguments;
					arguments.compositionSource = focusedComposition;
					arguments.eventSource = focusedComposition;
					focusedComposition->GetEventReceiver()->gotFocus.Execute(arguments);
				}
			}

			void GuiGraphicsHost::DisconnectCompositionInternal(GuiGraphicsComposition* composition)
			{
				// TODO: (enumerable) foreach
				for(vint i=0;i<composition->Children().Count();i++)
				{
					DisconnectCompositionInternal(composition->Children().Get(i));
				}
				if(mouseCaptureComposition==composition)
				{
					if(hostRecord.nativeWindow)
					{
						hostRecord.nativeWindow->ReleaseCapture();
					}
					mouseCaptureComposition=0;
				}
				if(focusedComposition==composition)
				{
					focusedComposition=0;
				}
				mouseEnterCompositions.Remove(composition);
			}

			void GuiGraphicsHost::MouseCapture(const NativeWindowMouseInfo& info)
			{
				if (hostRecord.nativeWindow && (info.left || info.middle || info.right))
				{
					if (!hostRecord.nativeWindow->IsCapturing() && !info.nonClient)
					{
						hostRecord.nativeWindow->RequireCapture();
						auto point = hostRecord.nativeWindow->Convert(NativePoint(info.x, info.y));
						mouseCaptureComposition = windowComposition->FindVisibleComposition(point, true);
					}
				}
			}

			void GuiGraphicsHost::MouseUncapture(const NativeWindowMouseInfo& info)
			{
				if(hostRecord.nativeWindow && !(info.left || info.middle || info.right))
				{
					hostRecord.nativeWindow->ReleaseCapture();
					mouseCaptureComposition=0;
				}
			}

			void GuiGraphicsHost::OnCharInput(const NativeWindowCharInfo& info, GuiGraphicsComposition* composition, GuiCharEvent GuiGraphicsEventReceiver::* eventReceiverEvent)
			{
				List<GuiGraphicsComposition*> compositions;
				GuiCharEventArgs arguments(composition);
				(NativeWindowCharInfo&)arguments = info;

				while (composition)
				{
					if (composition->HasEventReceiver())
					{
						if (!arguments.eventSource)
						{
							arguments.eventSource = composition;
						}
						compositions.Add(composition);
					}
					composition = composition->GetParent();
				}

				// TODO: (enumerable) foreach:reversed
				for(vint i=compositions.Count()-1;i>=0;i--)
				{
					compositions[i]->GetEventReceiver()->previewCharInput.Execute(arguments);
					if(arguments.handled)
					{
						return;
					}
				}

				// TODO: (enumerable) foreach
				for(vint i=0;i<compositions.Count();i++)
				{
					(compositions[i]->GetEventReceiver()->*eventReceiverEvent).Execute(arguments);
					if(arguments.handled)
					{
						return;
					}
				}
			}

			void GuiGraphicsHost::OnKeyInput(const NativeWindowKeyInfo& info, GuiGraphicsComposition* composition, GuiKeyEvent GuiGraphicsEventReceiver::* eventReceiverEvent)
			{
				List<GuiGraphicsComposition*> compositions;
				GuiKeyEventArgs arguments(composition);
				(NativeWindowKeyInfo&)arguments = info;

				while (composition)
				{
					if (composition->HasEventReceiver())
					{
						if (!arguments.eventSource)
						{
							arguments.eventSource = composition;
						}
						compositions.Add(composition);
					}
					composition = composition->GetParent();
				}

				// TODO: (enumerable) foreach:reversed
				for (vint i = compositions.Count() - 1; i >= 0; i--)
				{
					compositions[i]->GetEventReceiver()->previewKey.Execute(arguments);
					if (arguments.handled)
					{
						return;
					}
				}

				// TODO: (enumerable) foreach
				for (vint i = 0; i < compositions.Count(); i++)
				{
					(compositions[i]->GetEventReceiver()->*eventReceiverEvent).Execute(arguments);
					if (arguments.handled)
					{
						return;
					}
				}
			}

			void GuiGraphicsHost::RaiseMouseEvent(GuiMouseEventArgs& arguments, GuiGraphicsComposition* composition, GuiMouseEvent GuiGraphicsEventReceiver::* eventReceiverEvent)
			{
				arguments.compositionSource=composition;
				arguments.eventSource=0;
				vint x=arguments.x;
				vint y=arguments.y;

				while(composition)
				{
					if(composition->HasEventReceiver())
					{
						if(!arguments.eventSource)
						{
							arguments.eventSource=composition;
						}
						GuiGraphicsEventReceiver* eventReceiver=composition->GetEventReceiver();
						(eventReceiver->*eventReceiverEvent).Execute(arguments);
						if(arguments.handled)
						{
							break;
						}
					}

					GuiGraphicsComposition* parent=composition->GetParent();
					if(parent)
					{
						Rect parentBounds=parent->GetCachedBounds();
						Rect clientArea=parent->GetCachedClientArea();
						Rect childBounds=composition->GetCachedBounds();

						x+=childBounds.x1+(clientArea.x1-parentBounds.x1);
						y+=childBounds.y1+(clientArea.y1-parentBounds.y1);
						arguments.x=x;
						arguments.y=y;
					}
					composition=parent;
				}
			}

			void GuiGraphicsHost::OnMouseInput(const NativeWindowMouseInfo& info, bool capture, bool release, GuiMouseEvent GuiGraphicsEventReceiver::* eventReceiverEvent)
			{
				if (capture) MouseCapture(info);
				GuiGraphicsComposition* composition = 0;
				if (mouseCaptureComposition)
				{
					composition = mouseCaptureComposition;
				}
				else
				{
					auto point = hostRecord.nativeWindow->Convert(NativePoint(info.x, info.y));
					composition = windowComposition->FindVisibleComposition(point, true);
				}
				if (release) MouseUncapture(info);

				if (composition)
				{
					Rect bounds = composition->GetGlobalBounds();
					Point point = hostRecord.nativeWindow->Convert(NativePoint(info.x, info.y));
					GuiMouseEventArgs arguments;
					arguments.ctrl = info.ctrl;
					arguments.shift = info.shift;
					arguments.left = info.left;
					arguments.middle = info.middle;
					arguments.right = info.right;
					arguments.wheel = info.wheel;
					arguments.nonClient = info.nonClient;
					arguments.x = point.x - bounds.x1;
					arguments.y = point.y - bounds.y1;
					RaiseMouseEvent(arguments, composition, eventReceiverEvent);
				}
			}

			void GuiGraphicsHost::ResetRenderTarget()
			{
				windowComposition->UpdateRelatedHostRecord(nullptr);
			}

			void GuiGraphicsHost::CreateRenderTarget()
			{
				GetGuiGraphicsResourceManager()->RecreateRenderTarget(hostRecord.nativeWindow);
				RefreshRelatedHostRecord(hostRecord.nativeWindow);
			}

			INativeWindowListener::HitTestResult GuiGraphicsHost::HitTest(NativePoint location)
			{
				NativeRect bounds = hostRecord.nativeWindow->GetBounds();
				NativeRect clientBounds = hostRecord.nativeWindow->GetClientBoundsInScreen();
				NativePoint clientLocation(location.x + bounds.x1 - clientBounds.x1, location.y + bounds.y1 - clientBounds.y1);
				auto point = hostRecord.nativeWindow->Convert(clientLocation);
				if (auto hitComposition = windowComposition->FindVisibleComposition(point, true))
				{
					return hitComposition->GetRelatedHitTestResult();
				}
				return INativeWindowListener::NoDecision;
			}

			void GuiGraphicsHost::Moving(NativeRect& bounds, bool fixSizeOnly, bool draggingBorder)
			{
				NativeRect oldBounds = hostRecord.nativeWindow->GetBounds();
				minSize = windowComposition->GetCachedMinSize();
				NativeSize minWindowSize = hostRecord.nativeWindow->Convert(minSize) + (oldBounds.GetSize() - hostRecord.nativeWindow->GetClientSize());
				NativeWindowListener_Moving(hostRecord.nativeWindow, minWindowSize, bounds, fixSizeOnly, draggingBorder);
			}

			void GuiGraphicsHost::Moved()
			{
				RequestUpdateSizeFromNativeWindow();
			}

			void GuiGraphicsHost::DpiChanged(bool preparing)
			{
				if (preparing)
				{
					ResetRenderTarget();
				}
				else
				{
					CreateRenderTarget();
					needRender = true;
				}
			}

			void GuiGraphicsHost::Paint()
			{
				if (!supressPaint)
				{
					needRender = true;
				}
			}

			void GuiGraphicsHost::LeftButtonDown(const NativeWindowMouseInfo& info)
			{
				altActionManager->CloseAltHost();
				OnMouseInput(info, true, false, &GuiGraphicsEventReceiver::leftButtonDown);
			}

			void GuiGraphicsHost::LeftButtonUp(const NativeWindowMouseInfo& info)
			{
				OnMouseInput(info, false, true, &GuiGraphicsEventReceiver::leftButtonUp);
			}

			void GuiGraphicsHost::LeftButtonDoubleClick(const NativeWindowMouseInfo& info)
			{
				altActionManager->CloseAltHost();
				OnMouseInput(info, false, false, &GuiGraphicsEventReceiver::leftButtonDown);
				OnMouseInput(info, false, false, &GuiGraphicsEventReceiver::leftButtonDoubleClick);
			}

			void GuiGraphicsHost::RightButtonDown(const NativeWindowMouseInfo& info)
			{
				altActionManager->CloseAltHost();
				OnMouseInput(info, true, false, &GuiGraphicsEventReceiver::rightButtonDown);
			}

			void GuiGraphicsHost::RightButtonUp(const NativeWindowMouseInfo& info)
			{
				OnMouseInput(info, false, true, &GuiGraphicsEventReceiver::rightButtonUp);
			}

			void GuiGraphicsHost::RightButtonDoubleClick(const NativeWindowMouseInfo& info)
			{
				altActionManager->CloseAltHost();
				OnMouseInput(info, false, false, &GuiGraphicsEventReceiver::rightButtonDown);
				OnMouseInput(info, false, false, &GuiGraphicsEventReceiver::rightButtonDoubleClick);
			}

			void GuiGraphicsHost::MiddleButtonDown(const NativeWindowMouseInfo& info)
			{
				altActionManager->CloseAltHost();
				OnMouseInput(info, true, false, &GuiGraphicsEventReceiver::middleButtonDown);
			}

			void GuiGraphicsHost::MiddleButtonUp(const NativeWindowMouseInfo& info)
			{
				OnMouseInput(info, false, true, &GuiGraphicsEventReceiver::middleButtonUp);
			}

			void GuiGraphicsHost::MiddleButtonDoubleClick(const NativeWindowMouseInfo& info)
			{
				altActionManager->CloseAltHost();
				OnMouseInput(info, false, false, &GuiGraphicsEventReceiver::middleButtonDown);
				OnMouseInput(info, false, false, &GuiGraphicsEventReceiver::middleButtonDoubleClick);
			}

			void GuiGraphicsHost::HorizontalWheel(const NativeWindowMouseInfo& info)
			{
				OnMouseInput(info, false, false, &GuiGraphicsEventReceiver::horizontalWheel);
			}

			void GuiGraphicsHost::VerticalWheel(const NativeWindowMouseInfo& info)
			{
				OnMouseInput(info, false, false, &GuiGraphicsEventReceiver::verticalWheel);
			}

			void GuiGraphicsHost::MouseMoving(const NativeWindowMouseInfo& info)
			{
				CompositionList newCompositions;
				{
					auto point = hostRecord.nativeWindow->Convert(NativePoint(info.x, info.y));
					GuiGraphicsComposition* composition = windowComposition->FindVisibleComposition(point, true);
					while (composition)
					{
						newCompositions.Insert(0, composition);
						composition = composition->GetParent();
					}
				}

				vint firstDifferentIndex = mouseEnterCompositions.Count();
				// TODO: (enumerable) foreach:indexed
				for (vint i = 0; i < mouseEnterCompositions.Count(); i++)
				{
					if (i == newCompositions.Count())
					{
						firstDifferentIndex = newCompositions.Count();
						break;
					}
					if (mouseEnterCompositions[i] != newCompositions[i])
					{
						firstDifferentIndex = i;
						break;
					}
				}

				// TODO: (enumerable) foreach:reversed Linq:Take
				for (vint i = mouseEnterCompositions.Count() - 1; i >= firstDifferentIndex; i--)
				{
					GuiGraphicsComposition* composition = mouseEnterCompositions[i];
					if (composition->HasEventReceiver())
					{
						composition->GetEventReceiver()->mouseLeave.Execute(GuiEventArgs(composition));
					}
				}

				CopyFrom(mouseEnterCompositions, newCompositions);
				// TODO: (enumerable) foreach Linq:Skip
				for (vint i = firstDifferentIndex; i < mouseEnterCompositions.Count(); i++)
				{
					GuiGraphicsComposition* composition = mouseEnterCompositions[i];
					if (composition->HasEventReceiver())
					{
						composition->GetEventReceiver()->mouseEnter.Execute(GuiEventArgs(composition));
					}
				}

				INativeCursor* cursor = 0;
				if (newCompositions.Count() > 0)
				{
					cursor = newCompositions[newCompositions.Count() - 1]->GetRelatedCursor();
				}
				if (cursor)
				{
					hostRecord.nativeWindow->SetWindowCursor(cursor);
				}
				else
				{
					hostRecord.nativeWindow->SetWindowCursor(GetCurrentController()->ResourceService()->GetDefaultSystemCursor());
				}

				OnMouseInput(info, false, false, &GuiGraphicsEventReceiver::mouseMove);
			}

			void GuiGraphicsHost::MouseEntered()
			{
			}

			void GuiGraphicsHost::MouseLeaved()
			{
				// TODO: (enumerable) foreach:reversed
				for (vint i = mouseEnterCompositions.Count() - 1; i >= 0; i--)
				{
					GuiGraphicsComposition* composition = mouseEnterCompositions[i];
					if (composition->HasEventReceiver())
					{
						composition->GetEventReceiver()->mouseLeave.Execute(GuiEventArgs(composition));
					}
				}
				mouseEnterCompositions.Clear();
			}

			void GuiGraphicsHost::KeyDown(const NativeWindowKeyInfo& info)
			{
				if (altActionManager->KeyDown(info)) { return; }
				if (tabActionManager->KeyDown(info, focusedComposition)) { return; }
				if(shortcutKeyManager && shortcutKeyManager->Execute(info)) { return; }

				auto receiver = focusedComposition;
				if (!receiver) receiver = controlHost->GetFocusableComposition();
				if (!receiver) receiver = controlHost->GetBoundsComposition();

				if (receiver && receiver->HasEventReceiver())
				{
					OnKeyInput(info, receiver, &GuiGraphicsEventReceiver::keyDown);
				}
			}

			void GuiGraphicsHost::KeyUp(const NativeWindowKeyInfo& info)
			{
				if (altActionManager->KeyUp(info)) { return; }
				if (!info.ctrl && !info.shift && info.code == VKEY::KEY_MENU && hostRecord.nativeWindow)
				{
					hostRecord.nativeWindow->SupressAlt();
				}

				auto receiver = focusedComposition;
				if (!receiver) receiver = controlHost->GetFocusableComposition();
				if (!receiver) receiver = controlHost->GetBoundsComposition();

				if(receiver && receiver->HasEventReceiver())
				{
					OnKeyInput(info, receiver, &GuiGraphicsEventReceiver::keyUp);
				}
			}

			void GuiGraphicsHost::Char(const NativeWindowCharInfo& info)
			{
				if (altActionManager->Char(info)) { return; }
				if (tabActionManager->Char(info)) { return; }

				auto receiver = focusedComposition;
				if (!receiver) receiver = controlHost->GetFocusableComposition();
				if (!receiver) receiver = controlHost->GetBoundsComposition();

				if(receiver && receiver->HasEventReceiver())
				{
					OnCharInput(info, receiver, &GuiGraphicsEventReceiver::charInput);
				}
			}

			bool GuiGraphicsHost::NeedRefresh()
			{
				return needRender;
			}

			void GuiGraphicsHost::ForceRefresh(bool handleFailure, bool& updated, bool& failureByResized, bool& failureByLostDevice)
			{
				if (hostRecord.nativeWindow && hostRecord.nativeWindow->IsVisible())
				{
					auto result = Render(true, handleFailure, updated);
					failureByResized |= result == RenderTargetFailure::ResizeWhileRendering;
					failureByLostDevice |= result == RenderTargetFailure::LostDevice;
				}
				else
				{
					updated = false;
					failureByResized = false;
					failureByLostDevice = false;
				}
			}

			void GuiGraphicsHost::GlobalTimer()
			{
				timerManager.Play();

				DateTime now = DateTime::UtcTime();
				if (now.osMilliseconds - lastCaretTime >= CaretInterval)
				{
					lastCaretTime = now.osMilliseconds;
					if (focusedComposition && focusedComposition->HasEventReceiver())
					{
						focusedComposition->GetEventReceiver()->caretNotify.Execute(GuiEventArgs(focusedComposition));
					}
				}

				if (hostRecord.nativeWindow && hostRecord.nativeWindow->IsVisible() && hostRecord.nativeWindow->IsActivelyRefreshing())
				{
					bool updated = false;
					Render(false, true, updated);
				}
			}

			elements::RenderTargetFailure GuiGraphicsHost::Render(bool forceUpdate, bool handleFailure, bool& updated)
			{
				RenderTargetFailure result = RenderTargetFailure::None;

				if (!renderingTriggeredInLastFrame && needRender)
				{
					GuiControlSignalEventArgs arguments(controlHost->boundsComposition);
					arguments.controlSignal = ControlSignal::UpdateRequested;
					controlHost->ControlSignalTrigerred.Execute(arguments);
				}
				else if (renderingTriggeredInLastFrame && !needRender)
				{
					GuiControlSignalEventArgs arguments(controlHost->boundsComposition);
					arguments.controlSignal = ControlSignal::UpdateFullfilled;
					controlHost->ControlSignalTrigerred.Execute(arguments);
				}

				updated = needRender;
				renderingTriggeredInLastFrame = needRender;

				if (!forceUpdate && !needRender)
				{
					return result;
				}
				needRender = false;

				if(hostRecord.nativeWindow && hostRecord.nativeWindow->IsVisible())
				{
					supressPaint = true;
					{
						hostRecord.renderTarget->StartRendering();
						auto nativeOffset = hostRecord.nativeWindow->GetRenderingOffset();
						auto localOffset = hostRecord.nativeWindow->Convert(nativeOffset);
						windowComposition->Render(localOffset);
						result = hostRecord.renderTarget->StopRendering();
						hostRecord.nativeWindow->RedrawContent();
					}
					supressPaint = false;

					switch (result)
					{
					case RenderTargetFailure::ResizeWhileRendering:
						if (handleFailure)
						{
							GetGuiGraphicsResourceManager()->ResizeRenderTarget(hostRecord.nativeWindow);
							needRender = true;
						}
						break;
					case RenderTargetFailure::LostDevice:
						if (handleFailure)
						{
							ResetRenderTarget();
							CreateRenderTarget();
							needRender = true;
						}
						break;
					default:
						{
							supressPaint = true;
							auto bounds = windowComposition->GetCachedBounds();
							windowComposition->Layout_UpdateMinSize();
							auto preferred = windowComposition->GetCachedMinSize();
							auto width = bounds.Width() > preferred.x ? bounds.Width() : preferred.x;
							auto height = bounds.Height() > preferred.y ? bounds.Height() : preferred.y;
							controlHost->UpdateClientSizeAfterRendering(preferred, Size(width, height));
							windowComposition->Layout_UpdateBounds({ width,height });
							hostRecord.nativeWindow->SuggestMinClientSize(hostRecord.nativeWindow->Convert(windowComposition->GetCachedMinSize()));
							supressPaint = false;
						}
					}
				}

				if (!needRender)
				{
					{
						ProcList procs;
						CopyFrom(procs, afterRenderProcs);
						afterRenderProcs.Clear();
						// TODO: (enumerable) foreach
						for (vint i = 0; i < procs.Count(); i++)
						{
							procs[i]();
						}
					}
					{
						ProcMap procs;
						CopyFrom(procs, afterRenderKeyedProcs);
						afterRenderKeyedProcs.Clear();
						// TODO: (enumerable) foreach
						for (vint i = 0; i < procs.Count(); i++)
						{
							procs.Values()[i]();
						}
					}
				}

				return result;
			}

			GuiGraphicsHost::GuiGraphicsHost(controls::GuiControlHost* _controlHost, GuiGraphicsComposition* boundsComposition)
				:controlHost(_controlHost)
			{
				altActionManager = new GuiAltActionManager(controlHost);
				tabActionManager = new GuiTabActionManager(controlHost);
				hostRecord.host = this;
				windowComposition=new GuiWindowComposition;
				windowComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				windowComposition->AddChild(boundsComposition);
				RefreshRelatedHostRecord(nullptr);
			}

			GuiGraphicsHost::~GuiGraphicsHost()
			{
				windowComposition->RemoveChild(windowComposition->Children()[0]);
				NotifyFinalizeInstance(windowComposition);

				delete altActionManager;
				delete tabActionManager;
				if (shortcutKeyManager)
				{
					delete shortcutKeyManager;
					shortcutKeyManager = nullptr;
				}

				delete windowComposition;
			}

			INativeWindow* GuiGraphicsHost::GetNativeWindow()
			{
				return hostRecord.nativeWindow;
			}

			void GuiGraphicsHost::SetNativeWindow(INativeWindow* _nativeWindow)
			{
				if (hostRecord.nativeWindow != _nativeWindow)
				{
					if (hostRecord.nativeWindow)
					{
						GetCurrentController()->CallbackService()->UninstallListener(this);
						hostRecord.nativeWindow->UninstallListener(this);
					}

					if (_nativeWindow)
					{
						_nativeWindow->InstallListener(this);
						GetCurrentController()->CallbackService()->InstallListener(this);
						previousClientSize = _nativeWindow->GetClientSize();
						minSize = windowComposition->GetCachedMinSize();
						_nativeWindow->SetCaretPoint(_nativeWindow->Convert(caretPoint));
						needRender = true;
					}

					RefreshRelatedHostRecord(_nativeWindow);
				}
			}

			GuiGraphicsComposition* GuiGraphicsHost::GetMainComposition()
			{
				return windowComposition;
			}

			void GuiGraphicsHost::RequestRender()
			{
				needRender = true;
			}

			void GuiGraphicsHost::RequestUpdateSizeFromNativeWindow()
			{
				NativeSize size = hostRecord.nativeWindow->GetClientSize();
				if (previousClientSize != size)
				{
					previousClientSize = size;
					windowComposition->Layout_UpdateMinSize();
					windowComposition->Layout_UpdateBounds(hostRecord.nativeWindow->Convert(size));
					minSize = windowComposition->GetCachedMinSize();
					needRender = true;
				}
			}

			void GuiGraphicsHost::InvokeAfterRendering(const Func<void()>& proc, ProcKey key)
			{
				if (key.key == nullptr)
				{
					afterRenderProcs.Add(proc);
				}
				else
				{
					afterRenderKeyedProcs.Set(key, proc);
				}
			}

			void GuiGraphicsHost::InvalidateTabOrderCache()
			{
				tabActionManager->InvalidateTabOrderCache();
			}

			IGuiShortcutKeyManager* GuiGraphicsHost::GetShortcutKeyManager()
			{
				return shortcutKeyManager;
			}

			void GuiGraphicsHost::SetShortcutKeyManager(IGuiShortcutKeyManager* value)
			{
				shortcutKeyManager=value;
			}

			bool GuiGraphicsHost::SetFocus(GuiGraphicsComposition* composition)
			{
				if(!composition || composition->GetRelatedGraphicsHost()!=this)
				{
					return false;
				}
				if(focusedComposition == composition)
				{
					return true;
				}
				SetFocusInternal(composition);
				return true;
			}

			bool GuiGraphicsHost::ClearFocus()
			{
				if (!focusedComposition) return false;
				SetFocusInternal(nullptr);
				return true;
			}

			GuiGraphicsComposition* GuiGraphicsHost::GetFocusedComposition()
			{
				return focusedComposition;
			}

			Point GuiGraphicsHost::GetCaretPoint()
			{
				return caretPoint;
			}

			void GuiGraphicsHost::SetCaretPoint(Point value, GuiGraphicsComposition* referenceComposition)
			{
				if (referenceComposition)
				{
					Rect bounds = referenceComposition->GetGlobalBounds();
					value.x += bounds.x1;
					value.y += bounds.y1;
				}
				caretPoint = value;
				if (hostRecord.nativeWindow)
				{
					hostRecord.nativeWindow->SetCaretPoint(hostRecord.nativeWindow->Convert(caretPoint));
				}
			}

			GuiGraphicsTimerManager* GuiGraphicsHost::GetTimerManager()
			{
				return &timerManager;
			}

			void GuiGraphicsHost::DisconnectComposition(GuiGraphicsComposition* composition)
			{
				DisconnectCompositionInternal(composition);
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\GRAPHICSHOST\GUIGRAPHICSHOST_ALT.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace collections;
			using namespace controls;
			using namespace theme;

			const wchar_t* const IGuiAltAction::Identifier = L"vl::presentation::compositions::IGuiAltAction";
			const wchar_t* const IGuiAltActionContainer::Identifier = L"vl::presentation::compositions::IGuiAltActionContainer";
			const wchar_t* const IGuiAltActionHost::Identifier = L"vl::presentation::compositions::IGuiAltActionHost";

/***********************************************************************
IGuiAltAction
***********************************************************************/

			bool IGuiAltAction::IsLegalAlt(const WString& alt)
			{
				for (vint i = 0; i < alt.Length(); i++)
				{
					auto c = alt[i];
					if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))
					{
						continue;
					}
					return false;
				}
				return true;
			}

/***********************************************************************
IGuiAltActionHost
***********************************************************************/

			void IGuiAltActionHost::CollectAltActionsFromControl(controls::GuiControl* control, bool includeThisControl, collections::Group<WString, IGuiAltAction*>& actions)
			{
				List<GuiControl*> controls;
				controls.Add(control);
				vint index = 0;

				while (index < controls.Count())
				{
					auto current = controls[index++];

					if (current != control || includeThisControl)
					{
						if (auto container = current->QueryTypedService<IGuiAltActionContainer>())
						{
							vint count = container->GetAltActionCount();
							for (vint i = 0; i < count; i++)
							{
								auto action = container->GetAltAction(i);
								actions.Add(action->GetAlt(), action);
							}
							continue;
						}
						else if (auto action = current->QueryTypedService<IGuiAltAction>())
						{
							if (action->IsAltAvailable())
							{
								if (action->IsAltEnabled())
								{
									actions.Add(action->GetAlt(), action);
									continue;
								}
							}
						}
					}

					vint count = current->GetChildrenCount();
					for (vint i = 0; i < count; i++)
					{
						controls.Add(current->GetChild(i));
					}
				}
			}

/***********************************************************************
GuiAltActionHostBase
***********************************************************************/

			void GuiAltActionHostBase::SetAltComposition(GuiGraphicsComposition* _composition)
			{
				composition = _composition;
			}

			void GuiAltActionHostBase::SetAltControl(controls::GuiControl* _control, bool _includeControl)
			{
				control = _control;
				includeControl = _includeControl;
			}

			GuiGraphicsComposition* GuiAltActionHostBase::GetAltComposition()
			{
				CHECK_ERROR(composition, L"GuiAltActionHostBase::GetAltComposition()#Need to call SetAltComposition.");
				return composition;
			}

			IGuiAltActionHost* GuiAltActionHostBase::GetPreviousAltHost()
			{
				return previousHost;
			}

			void GuiAltActionHostBase::OnActivatedAltHost(IGuiAltActionHost* _previousHost)
			{
				previousHost = _previousHost;
			}

			void GuiAltActionHostBase::OnDeactivatedAltHost()
			{
				previousHost = nullptr;
			}

			void GuiAltActionHostBase::CollectAltActions(collections::Group<WString, IGuiAltAction*>& actions)
			{
				CHECK_ERROR(control, L"GuiAltActionHostBase::CollectAltActions(Group<WString, IGuiAltAction*>&)#Need to call SetAltControl.");
				CollectAltActionsFromControl(control, includeControl, actions);
			}

/***********************************************************************
GuiAltActionManager
***********************************************************************/

			void GuiAltActionManager::EnterAltHost(IGuiAltActionHost* host)
			{
				ClearAltHost();

				Group<WString, IGuiAltAction*> actions;
				host->CollectAltActions(actions);
				if (actions.Count() == 0)
				{
					CloseAltHost();
					return;
				}

				host->OnActivatedAltHost(currentAltHost);
				currentAltHost = host;
				CreateAltTitles(actions);
			}

			void GuiAltActionManager::LeaveAltHost()
			{
				if (currentAltHost)
				{
					ClearAltHost();
					auto previousHost = currentAltHost->GetPreviousAltHost();
					currentAltHost->OnDeactivatedAltHost();
					currentAltHost = previousHost;

					if (currentAltHost)
					{
						Group<WString, IGuiAltAction*> actions;
						currentAltHost->CollectAltActions(actions);
						CreateAltTitles(actions);
					}
				}
			}

			bool GuiAltActionManager::EnterAltKey(wchar_t key)
			{
				currentAltPrefix += WString::FromChar(key);
				vint index = currentActiveAltActions.Keys().IndexOf(currentAltPrefix);
				if (index == -1)
				{
					if (FilterTitles() == 0)
					{
						currentAltPrefix = currentAltPrefix.Left(currentAltPrefix.Length() - 1);
						FilterTitles();
					}
				}
				else
				{
					auto action = currentActiveAltActions.Values()[index];
					if (action->GetActivatingAltHost())
					{
						EnterAltHost(action->GetActivatingAltHost());
					}
					else
					{
						CloseAltHost();
					}
					action->OnActiveAlt();
					return true;
				}
				return false;
			}

			void GuiAltActionManager::LeaveAltKey()
			{
				if (currentAltPrefix.Length() >= 1)
				{
					currentAltPrefix = currentAltPrefix.Left(currentAltPrefix.Length() - 1);
				}
				FilterTitles();
			}

			void GuiAltActionManager::CreateAltTitles(const collections::Group<WString, IGuiAltAction*>& actions)
			{
				if (currentAltHost)
				{
					// TODO: (enumerable) foreach on group (key, value[])
					vint count = actions.Count();
					for (vint i = 0; i < count; i++)
					{
						WString key = actions.Keys()[i];
						const auto& values = actions.GetByIndex(i);
						vint numberLength = 0;
						if (values.Count() == 1 && key.Length() > 0)
						{
							numberLength = 0;
						}
						else if (values.Count() <= 10)
						{
							numberLength = 1;
						}
						else if (values.Count() <= 100)
						{
							numberLength = 2;
						}
						else if (values.Count() <= 1000)
						{
							numberLength = 3;
						}
						else
						{
							continue;
						}

						for (auto [action, index] : indexed(values))
						{
							WString key = actions.Keys()[i];
							if (numberLength > 0)
							{
								WString number = itow(index);
								while (number.Length() < numberLength)
								{
									number = L"0" + number;
								}
								key += number;
							}
							currentActiveAltActions.Add(key, action);
						}
					}

					// TODO: (enumerable) foreach on dictionary
					count = currentActiveAltActions.Count();
					auto window = dynamic_cast<GuiWindow*>(currentAltHost->GetAltComposition()->GetRelatedControlHost());
					for (vint i = 0; i < count; i++)
					{
						auto key = currentActiveAltActions.Keys()[i];
						auto composition = currentActiveAltActions.Values()[i]->GetAltComposition();

						auto label = new GuiLabel(theme::ThemeName::ShortcutKey);
						if (auto labelStyle = window->TypedControlTemplateObject(true)->GetShortcutKeyTemplate())
						{
							label->SetControlTemplate(labelStyle);
						}
						label->SetText(key);
						composition->AddChild(label->GetBoundsComposition());
						currentActiveAltTitles.Add(key, label);
					}

					FilterTitles();
				}
			}

			vint GuiAltActionManager::FilterTitles()
			{
				// TODO: (enumerable) foreach on dictionary
				vint count = currentActiveAltTitles.Count();
				vint visibles = 0;
				for (vint i = 0; i < count; i++)
				{
					auto key = currentActiveAltTitles.Keys()[i];
					auto value = currentActiveAltTitles.Values()[i];
					if (key.Length() >= currentAltPrefix.Length() && key.Left(currentAltPrefix.Length()) == currentAltPrefix)
					{
						value->SetVisible(true);
						if (currentAltPrefix.Length() <= key.Length())
						{
							value->SetText(
								key
								.Insert(currentAltPrefix.Length(), L"[")
								.Insert(currentAltPrefix.Length() + 2, L"]")
								);
						}
						else
						{
							value->SetText(key);
						}
						visibles++;
					}
					else
					{
						value->SetVisible(false);
					}
				}
				return visibles;
			}

			void GuiAltActionManager::ClearAltHost()
			{
				for (auto title : currentActiveAltTitles.Values())
				{
					SafeDeleteControl(title);
				}
				currentActiveAltActions.Clear();
				currentActiveAltTitles.Clear();
				currentAltPrefix = L"";
			}

			void GuiAltActionManager::CloseAltHost()
			{
				ClearAltHost();
				while (currentAltHost)
				{
					currentAltHost->OnDeactivatedAltHost();
					currentAltHost = currentAltHost->GetPreviousAltHost();
				}
			}

			GuiAltActionManager::GuiAltActionManager(controls::GuiControlHost* _controlHost)
				:controlHost(_controlHost)
			{
			}

			GuiAltActionManager::~GuiAltActionManager()
			{
			}

			bool GuiAltActionManager::KeyDown(const NativeWindowKeyInfo& info)
			{
				if (!info.ctrl && !info.shift)
				{
					if (currentAltHost)
					{
						if (info.code == VKEY::KEY_ESCAPE)
						{
							LeaveAltHost();
							return true;
						}
						else if (info.code == VKEY::KEY_BACK)
						{
							LeaveAltKey();
						}
						else if (VKEY::KEY_NUMPAD0 <= info.code && info.code <= VKEY::KEY_NUMPAD9)
						{
							if (EnterAltKey((wchar_t)(L'0' + ((vint)info.code - (vint)VKEY::KEY_NUMPAD0))))
							{
								supressAltKey = info.code;
								return true;
							}
						}
						else if ((VKEY::KEY_0 <= info.code && info.code <= VKEY::KEY_9) || (VKEY::KEY_A <= info.code && info.code <= VKEY::KEY_Z))
						{
							if (EnterAltKey((wchar_t)info.code))
							{
								supressAltKey = info.code;
								return true;
							}
						}
					}
					else
					{
						if (info.code == VKEY::KEY_MENU)
						{
							if (auto altHost = controlHost->QueryTypedService<IGuiAltActionHost>())
							{
								if (!altHost->GetPreviousAltHost())
								{
									EnterAltHost(altHost);
								}
							}
						}
					}
				}

				if (currentAltHost)
				{
					return true;
				}
				return false;
			}

			bool GuiAltActionManager::KeyUp(const NativeWindowKeyInfo& info)
			{
				if (!info.ctrl && !info.shift && info.code == supressAltKey)
				{
					supressAltKey = VKEY::KEY_UNKNOWN;
					return true;
				}
				return false;
			}

			bool GuiAltActionManager::Char(const NativeWindowCharInfo& info)
			{
				if (currentAltHost || supressAltKey != VKEY::KEY_UNKNOWN)
				{
					return true;
				}
				return false;
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\GRAPHICSHOST\GUIGRAPHICSHOST_SHORTCUTKEY.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{

/***********************************************************************
GuiShortcutKeyItem
***********************************************************************/

			GuiShortcutKeyItem::GuiShortcutKeyItem(GuiShortcutKeyManager* _shortcutKeyManager, bool _global, bool _ctrl, bool _shift, bool _alt, VKEY _key)
				:shortcutKeyManager(_shortcutKeyManager)
				,global(_global)
				,ctrl(_ctrl)
				,shift(_shift)
				,alt(_alt)
				,key(_key)
			{
			}

			GuiShortcutKeyItem::~GuiShortcutKeyItem()
			{
			}

			IGuiShortcutKeyManager* GuiShortcutKeyItem::GetManager()
			{
				return shortcutKeyManager;
			}

			WString GuiShortcutKeyItem::GetName()
			{
				WString name;
				if (global) name += L"{";
				if (ctrl) name += L"Ctrl+";
				if (shift) name += L"Shift+";
				if (alt) name += L"Alt+";
				name += GetCurrentController()->InputService()->GetKeyName(key);
				if (global) name += L"}";
				return name;
			}

			void GuiShortcutKeyItem::ReadKeyConfig(bool& _ctrl, bool& _shift, bool& _alt, VKEY& _key)
			{
				_ctrl = ctrl;
				_shift = shift;
				_alt = alt;
				_key = key;
			}

			bool GuiShortcutKeyItem::CanActivate(const NativeWindowKeyInfo& info)
			{
				return
					info.ctrl==ctrl &&
					info.shift==shift &&
					info.alt==alt &&
					info.code==key;
			}

			bool GuiShortcutKeyItem::CanActivate(bool _ctrl, bool _shift, bool _alt, VKEY _key)
			{
				return
					_ctrl==ctrl &&
					_shift==shift &&
					_alt==alt &&
					_key==key;
			}

			void GuiShortcutKeyItem::Execute()
			{
				GuiEventArgs arguments;
				Executed.Execute(arguments);
			}

/***********************************************************************
GuiShortcutKeyManager
***********************************************************************/

			bool GuiShortcutKeyManager::IsGlobal()
			{
				return false;
			}

			bool GuiShortcutKeyManager::OnCreatingShortcut(GuiShortcutKeyItem* item)
			{
				return true;
			}

			void GuiShortcutKeyManager::OnDestroyingShortcut(GuiShortcutKeyItem* item)
			{
			}

			IGuiShortcutKeyItem* GuiShortcutKeyManager::CreateShortcutInternal(bool ctrl, bool shift, bool alt, VKEY key)
			{
				auto item = Ptr(new GuiShortcutKeyItem(this, IsGlobal(), ctrl, shift, alt, key));
				if (!OnCreatingShortcut(item.Obj())) return nullptr;
				shortcutKeyItems.Add(item);
				return item.Obj();
			}

			GuiShortcutKeyManager::GuiShortcutKeyManager()
			{
			}

			GuiShortcutKeyManager::~GuiShortcutKeyManager()
			{
				for (auto item : shortcutKeyItems)
				{
					OnDestroyingShortcut(item.Obj());
				}
			}

			vint GuiShortcutKeyManager::GetItemCount()
			{
				return shortcutKeyItems.Count();
			}

			IGuiShortcutKeyItem* GuiShortcutKeyManager::GetItem(vint index)
			{
				return shortcutKeyItems[index].Obj();
			}

			bool GuiShortcutKeyManager::Execute(const NativeWindowKeyInfo& info)
			{
				bool executed=false;
				for (auto item : shortcutKeyItems)
				{
					if(item->CanActivate(info))
					{
						item->Execute();
						executed=true;
					}
				}
				return executed;
			}

			IGuiShortcutKeyItem* GuiShortcutKeyManager::TryGetShortcut(bool ctrl, bool shift, bool alt, VKEY key)
			{
				for (auto item : shortcutKeyItems)
				{
					if (item->CanActivate(ctrl, shift, alt, key))
					{
						return item.Obj();
					}
				}
				return nullptr;
			}

			IGuiShortcutKeyItem* GuiShortcutKeyManager::CreateNewShortcut(bool ctrl, bool shift, bool alt, VKEY key)
			{
				CHECK_ERROR(
					TryGetShortcut(ctrl, shift, alt, key) == nullptr,
					L"vl::presentation::compositions::GuiShortcutKeyManager::CreateNewShortcut(bool, bool, bool, VKEY)#The shortcut key exists."
					);
				return CreateShortcutInternal(ctrl, shift, alt, key);
			}

			IGuiShortcutKeyItem* GuiShortcutKeyManager::CreateShortcutIfNotExist(bool ctrl, bool shift, bool alt, VKEY key)
			{
				if (TryGetShortcut(ctrl, shift, alt, key))
				{
					return nullptr;
				}
				return CreateShortcutInternal(ctrl, shift, alt, key);
			}

			bool GuiShortcutKeyManager::DestroyShortcut(IGuiShortcutKeyItem* item)
			{
				if (!item) return false;
				if (item->GetManager() != this) return false;

				auto skItem = dynamic_cast<GuiShortcutKeyItem*>(item);
				if (!skItem) return false;

				vint index = shortcutKeyItems.IndexOf(skItem);
				if (index == -1) return false;
				OnDestroyingShortcut(skItem);
				return shortcutKeyItems.RemoveAt(index);
			}
		}
	}
}

/***********************************************************************
.\APPLICATION\GRAPHICSHOST\GUIGRAPHICSHOST_TAB.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace collections;
			using namespace controls;

			const wchar_t* const IGuiTabAction::Identifier = L"vl::presentation::compositions::IGuiTabAction";

/***********************************************************************
GuiTabActionManager
***********************************************************************/

			namespace tab_focus
			{
				void CollectControls(GuiControl* current, bool includeCurrent, Group<vuint64_t, GuiControl*>& prioritized)
				{
					if (includeCurrent)
					{
						auto tabAction = current->QueryTypedService<IGuiTabAction>();
						if (tabAction && (tabAction->IsTabAvailable() || tabAction->GetTabPriority() != -1))
						{
							vint priority = tabAction->GetTabPriority();
							vuint64_t normalized = priority < 0 ? ~(vuint64_t)0 : (vuint64_t)priority;
							prioritized.Add(normalized, current);
							return;
						}
					}

					vint count = current->GetChildrenCount();
					for (vint i = 0; i < count; i++)
					{
						CollectControls(current->GetChild(i), true, prioritized);
					}
				}

				void InsertPrioritized(List<GuiControl*>& controls, vint index, Group<vuint64_t, GuiControl*>& prioritized)
				{
					// TODO: (enumerable) Linq:SelectMany
					vint count = prioritized.Count();
					for (vint i = 0; i < count; i++)
					{
						auto& values = prioritized.GetByIndex(i);
						for (vint j = 0; j < values.Count(); j++)
						{
							controls.Insert(index++, values[j]);
						}
					}
				}
			}
			using namespace tab_focus;

			void GuiTabActionManager::BuildControlList()
			{
				controlsInOrder.Clear();
				{
					Group<vuint64_t, GuiControl*> prioritized;
					CollectControls(controlHost, false, prioritized);
					InsertPrioritized(controlsInOrder, 0, prioritized);
				}

				// TODO: (enumerable) foreach
				for (vint i = 0; i < controlsInOrder.Count(); i++)
				{
					Group<vuint64_t, GuiControl*> prioritized;
					CollectControls(controlsInOrder[i], false, prioritized);
					InsertPrioritized(controlsInOrder, i + 1, prioritized);
				}
			}

			controls::GuiControl* GuiTabActionManager::GetNextFocusControl(controls::GuiControl* focusedControl, vint offset)
			{
				if (!available)
				{
					BuildControlList();
					available = true;
				}
#define STEP_AND_NORMALIZE(INDEX) (((INDEX) + offset + controlsInOrder.Count()) % controlsInOrder.Count())

				if (controlsInOrder.Count() == 0) return nullptr;
				vint startIndex = controlsInOrder.IndexOf(focusedControl);
				startIndex =
					startIndex == -1 ? 0 :
					STEP_AND_NORMALIZE(startIndex);

				vint index = startIndex;
				do
				{
					auto control = controlsInOrder[index];
					if (auto tabAction = control->QueryTypedService<IGuiTabAction>())
					{
						if (tabAction->IsTabAvailable() && tabAction->IsTabEnabled())
						{
							return control;
						}
					}

					index = STEP_AND_NORMALIZE(index);
				} while (index != startIndex);

#undef STEP_AND_NORMALIZE

				return nullptr;
			}

			GuiTabActionManager::GuiTabActionManager(controls::GuiControlHost* _controlHost)
				:controlHost(_controlHost)
			{
			}

			GuiTabActionManager::~GuiTabActionManager()
			{
			}

			void GuiTabActionManager::InvalidateTabOrderCache()
			{
				available = false;
				controlsInOrder.Clear();
			}

			bool GuiTabActionManager::KeyDown(const NativeWindowKeyInfo& info, GuiGraphicsComposition* focusedComposition)
			{
				if (!info.ctrl && !info.alt && info.code == VKEY::KEY_TAB)
				{
					GuiControl* focusedControl = nullptr;
					if (focusedComposition)
					{
						focusedControl = focusedComposition->GetRelatedControl();
						if (focusedControl && focusedControl->GetAcceptTabInput())
						{
							return false;
						}
					}

					if (auto next = GetNextFocusControl(focusedControl, (info.shift ? -1 : 1)))
					{
						next->SetFocused();
						supressTabOnce = true;
						return true;
					}
				}
				return false;
			}

			bool GuiTabActionManager::Char(const NativeWindowCharInfo& info)
			{
				bool supress = supressTabOnce;
				supressTabOnce = false;
				return supress && info.code == L'\t';
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\GUIBUTTONCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace elements;
			using namespace compositions;
			using namespace collections;
			using namespace reflection::description;

/***********************************************************************
GuiButton
***********************************************************************/

			void GuiButton::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiButton::AfterControlTemplateInstalled_(bool initialize)
			{
				TypedControlTemplateObject(true)->SetState(controlState);
			}

			void GuiButton::OnParentLineChanged()
			{
				GuiControl::OnParentLineChanged();
				if (GetRelatedControlHost() == 0)
				{
					mousePressingDirect = false;
					mousePressingIndirect = false;
					mouseHoving = false;
					UpdateControlState();
				}
			}

			void GuiButton::OnActiveAlt()
			{
				if (autoFocus)
				{
					GuiControl::OnActiveAlt();
				}
				BeforeClicked.Execute(GetNotifyEventArguments());
				Clicked.Execute(GetNotifyEventArguments());
				AfterClicked.Execute(GetNotifyEventArguments());
			}

			bool GuiButton::IsTabAvailable()
			{
				return autoFocus && GuiControl::IsTabAvailable();
			}

			void GuiButton::UpdateControlState()
			{
				auto newControlState = ButtonState::Normal;
				if (keyPressing)
				{
					newControlState = ButtonState::Pressed;
				}
				else if (mousePressingDirect || mousePressingIndirect)
				{
					if (mouseHoving)
					{
						newControlState = ButtonState::Pressed;
					}
					else
					{
						newControlState = ButtonState::Active;
					}
				}
				else
				{
					if (mouseHoving)
					{
						newControlState = ButtonState::Active;
					}
					else
					{
						newControlState = ButtonState::Normal;
					}
				}
				if (controlState != newControlState)
				{
					controlState = newControlState;
					TypedControlTemplateObject(true)->SetState(controlState);
				}
			}

			void GuiButton::CheckAndClick(bool skipChecking, compositions::GuiEventArgs& arguments)
			{
				if (!skipChecking)
				{
					auto eventSource = arguments.eventSource->GetAssociatedControl();
					while (eventSource && eventSource != this)
					{
						if (eventSource->GetFocusableComposition())
						{
							return;
						}
						eventSource = eventSource->GetParent();
					}
				}
				BeforeClicked.Execute(GetNotifyEventArguments());
				Clicked.Execute(GetNotifyEventArguments());
				AfterClicked.Execute(GetNotifyEventArguments());
			}

			void GuiButton::OnLeftButtonDown(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
			{
				if (arguments.eventSource == boundsComposition)
				{
					mousePressingDirect = true;
				}
				else if (!ignoreChildControlMouseEvents)
				{
					mousePressingIndirect = true;
				}

				if (mousePressingDirect || mousePressingIndirect)
				{
					if (GetVisuallyEnabled() && autoFocus)
					{
						SetFocused();
					}
					UpdateControlState();
					if (GetVisuallyEnabled() && !clickOnMouseUp)
					{
						CheckAndClick(mousePressingIndirect, arguments);
					}
				}
			}

			void GuiButton::OnLeftButtonUp(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
			{
				if (mousePressingDirect || mousePressingIndirect)
				{
					bool skipChecking = mousePressingIndirect;
					mousePressingDirect = false;
					mousePressingIndirect = false;
					UpdateControlState();
					if (GetVisuallyEnabled() && mouseHoving && clickOnMouseUp)
					{
						CheckAndClick(skipChecking, arguments);
					}
				}
			}

			void GuiButton::OnMouseEnter(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (arguments.eventSource == boundsComposition || !ignoreChildControlMouseEvents)
				{
					mouseHoving = true;
					UpdateControlState();
				}
			}

			void GuiButton::OnMouseLeave(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (arguments.eventSource == boundsComposition || !ignoreChildControlMouseEvents)
				{
					mouseHoving = false;
					UpdateControlState();
				}
			}
			
			void GuiButton::OnKeyDown(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
				if (arguments.eventSource == focusableComposition && !arguments.ctrl && !arguments.shift && !arguments.alt)
				{
					switch (arguments.code)
					{
					case VKEY::KEY_RETURN:
						CheckAndClick(false, arguments);
						arguments.handled = true;
						break;
					case VKEY::KEY_SPACE:
						if (!arguments.autoRepeatKeyDown)
						{
							keyPressing = true;
							UpdateControlState();
						}
						arguments.handled = true;
						break;
					default:;
					}
				}
			}

			void GuiButton::OnKeyUp(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
				if (arguments.eventSource == focusableComposition && !arguments.ctrl && !arguments.shift && !arguments.alt)
				{
					switch (arguments.code)
					{
					case VKEY::KEY_SPACE:
						if (keyPressing)
						{
							keyPressing = false;
							UpdateControlState();
							CheckAndClick(false, arguments);
						}
						arguments.handled = true;
						break;
					default:;
					}
				}
			}

			void GuiButton::OnLostFocus(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (keyPressing)
				{
					keyPressing = false;
					UpdateControlState();
				}
			}

			GuiButton::GuiButton(theme::ThemeName themeName)
				:GuiControl(themeName)
			{
				Clicked.SetAssociatedComposition(boundsComposition);
				SetFocusableComposition(boundsComposition);

				boundsComposition->GetEventReceiver()->leftButtonDown.AttachMethod(this, &GuiButton::OnLeftButtonDown);
				boundsComposition->GetEventReceiver()->leftButtonUp.AttachMethod(this, &GuiButton::OnLeftButtonUp);
				boundsComposition->GetEventReceiver()->mouseEnter.AttachMethod(this, &GuiButton::OnMouseEnter);
				boundsComposition->GetEventReceiver()->mouseLeave.AttachMethod(this, &GuiButton::OnMouseLeave);
				boundsComposition->GetEventReceiver()->keyDown.AttachMethod(this, &GuiButton::OnKeyDown);
				boundsComposition->GetEventReceiver()->keyUp.AttachMethod(this, &GuiButton::OnKeyUp);
				boundsComposition->GetEventReceiver()->lostFocus.AttachMethod(this, &GuiButton::OnLostFocus);
			}

			GuiButton::~GuiButton()
			{
			}

			bool GuiButton::GetClickOnMouseUp()
			{
				return clickOnMouseUp;
			}

			void GuiButton::SetClickOnMouseUp(bool value)
			{
				clickOnMouseUp=value;
			}

			bool GuiButton::GetAutoFocus()
			{
				return autoFocus;
			}

			void GuiButton::SetAutoFocus(bool value)
			{
				autoFocus = value;
			}

			bool GuiButton::GetIgnoreChildControlMouseEvents()
			{
				return ignoreChildControlMouseEvents;
			}

			void GuiButton::SetIgnoreChildControlMouseEvents(bool value)
			{
				ignoreChildControlMouseEvents = value;
			}

/***********************************************************************
GuiSelectableButton::GroupController
***********************************************************************/

			GuiSelectableButton::GroupController::GroupController()
			{
			}

			GuiSelectableButton::GroupController::~GroupController()
			{
				// TODO: (enumerable) foreach:reversed
				for(vint i=buttons.Count()-1;i>=0;i--)
				{
					buttons[i]->SetGroupController(0);
				}
			}

			void GuiSelectableButton::GroupController::Attach(GuiSelectableButton* button)
			{
				if(!buttons.Contains(button))
				{
					buttons.Add(button);
				}
			}

			void GuiSelectableButton::GroupController::Detach(GuiSelectableButton* button)
			{
				buttons.Remove(button);
			}

/***********************************************************************
GuiSelectableButton::MutexGroupController
***********************************************************************/

			GuiSelectableButton::MutexGroupController::MutexGroupController()
				:suppress(false)
			{
			}

			GuiSelectableButton::MutexGroupController::~MutexGroupController()
			{
			}

			void GuiSelectableButton::MutexGroupController::OnSelectedChanged(GuiSelectableButton* button)
			{
				if(!suppress)
				{
					suppress=true;
					// TODO: (enumerable) foreach
					for(vint i=0;i<buttons.Count();i++)
					{
						buttons[i]->SetSelected(buttons[i]==button);
					}
					suppress=false;
				}
			}

/***********************************************************************
GuiSelectableButton
***********************************************************************/

			void GuiSelectableButton::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiSelectableButton::AfterControlTemplateInstalled_(bool initialize)
			{
				TypedControlTemplateObject(true)->SetSelected(isSelected);
			}

			void GuiSelectableButton::OnAfterClicked(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if(autoSelection)
				{
					SetSelected(!GetSelected());
				}
			}

			GuiSelectableButton::GuiSelectableButton(theme::ThemeName themeName)
				:GuiButton(themeName)
			{
				GroupControllerChanged.SetAssociatedComposition(boundsComposition);
				AutoSelectionChanged.SetAssociatedComposition(boundsComposition);
				SelectedChanged.SetAssociatedComposition(boundsComposition);

				AfterClicked.AttachMethod(this, &GuiSelectableButton::OnAfterClicked);
			}
			
			GuiSelectableButton::~GuiSelectableButton()
			{
				if(groupController)
				{
					groupController->Detach(this);
				}
			}

			GuiSelectableButton::GroupController* GuiSelectableButton::GetGroupController()
			{
				return groupController;
			}

			void GuiSelectableButton::SetGroupController(GroupController* value)
			{
				if(groupController)
				{
					groupController->Detach(this);
				}
				groupController=value;
				if(groupController)
				{
					groupController->Attach(this);
				}
				GroupControllerChanged.Execute(GetNotifyEventArguments());
			}

			bool GuiSelectableButton::GetAutoSelection()
			{
				return autoSelection;
			}

			void GuiSelectableButton::SetAutoSelection(bool value)
			{
				if(autoSelection!=value)
				{
					autoSelection=value;
					AutoSelectionChanged.Execute(GetNotifyEventArguments());
				}
			}

			bool GuiSelectableButton::GetSelected()
			{
				return isSelected;
			}

			void GuiSelectableButton::SetSelected(bool value)
			{
				if (isSelected != value)
				{
					isSelected = value;
					TypedControlTemplateObject(true)->SetSelected(isSelected);
					if (groupController)
					{
						groupController->OnSelectedChanged(this);
					}
					SelectedChanged.Execute(GetNotifyEventArguments());
				}
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\GUICONTAINERCONTROLS.CPP
***********************************************************************/


namespace vl
{
	namespace presentation
	{
		using namespace compositions;

		namespace controls
		{
			using namespace reflection::description;

/***********************************************************************
GuiTabPage
***********************************************************************/

			bool GuiTabPage::IsAltAvailable()
			{
				return false;
			}

			GuiTabPage::GuiTabPage(theme::ThemeName themeName)
				:GuiCustomControl(themeName)
			{
			}

			GuiTabPage::~GuiTabPage()
			{
				FinalizeAggregation();
			}

			GuiTab* GuiTabPage::GetOwnerTab()
			{
				return tab;
			}

/***********************************************************************
GuiTabPageList
***********************************************************************/

			bool GuiTabPageList::QueryInsert(vint index, GuiTabPage* const& value)
			{
				return !items.Contains(value) && value->tab == nullptr;
			}

			void GuiTabPageList::AfterInsert(vint index, GuiTabPage* const& value)
			{
				value->tab = tab;
				value->SetVisible(false);
				value->boundsComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				tab->containerComposition->AddChild(value->boundsComposition);

				if (!tab->selectedPage)
				{
					tab->SetSelectedPage(value);
				}
			}

			void GuiTabPageList::BeforeRemove(vint index, GuiTabPage* const& value)
			{
				tab->containerComposition->RemoveChild(value->boundsComposition);
				value->tab = nullptr;

				if (items.Count() > 1)
				{
					if (items.Count() > index + 1)
					{
						tab->SetSelectedPage(items[index + 1]);
					}
					else if (items.Count() == index + 1)
					{
						tab->SetSelectedPage(items[index - 1]);
					}
				}
			}

			void GuiTabPageList::AfterRemove(vint index, vint count)
			{
				if (items.Count() == 0)
				{
					tab->SetSelectedPage(nullptr);
				}
			}

			GuiTabPageList::GuiTabPageList(GuiTab* _tab)
				:tab(_tab)
			{
			}

			GuiTabPageList::~GuiTabPageList()
			{
			}

/***********************************************************************
GuiTab::CommandExecutor
***********************************************************************/

			GuiTab::CommandExecutor::CommandExecutor(GuiTab* _tab)
				:tab(_tab)
			{
			}

			GuiTab::CommandExecutor::~CommandExecutor()
			{
			}

			void GuiTab::CommandExecutor::ShowTab(vint index, bool setFocus)
			{
				tab->SetSelectedPage(tab->GetPages().Get(index));
				if (setFocus)
				{
					tab->SetFocused();
				}
			}

/***********************************************************************
GuiTab
***********************************************************************/

			void GuiTab::BeforeControlTemplateUninstalled_()
			{
				auto ct = TypedControlTemplateObject(false);
				if (!ct) return;

				ct->SetCommands(nullptr);
				ct->SetTabPages(nullptr);
				ct->SetSelectedTabPage(nullptr);
			}

			void GuiTab::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				ct->SetCommands(commandExecutor.Obj());
				ct->SetTabPages(UnboxValue<Ptr<IValueObservableList>>(BoxParameter(tabPages)));
				ct->SetSelectedTabPage(selectedPage);
			}

			void GuiTab::OnKeyDown(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
				if (arguments.eventSource == focusableComposition)
				{
					if (auto ct = TypedControlTemplateObject(false))
					{
						vint index = tabPages.IndexOf(selectedPage);
						if (index != -1)
						{
							auto hint = ct->GetTabOrder();
							vint tabOffset = 0;
							switch (hint)
							{
							case TabPageOrder::LeftToRight:
								if (arguments.code == VKEY::KEY_LEFT) tabOffset = -1;
								else if (arguments.code == VKEY::KEY_RIGHT) tabOffset = 1;
								break;
							case TabPageOrder::RightToLeft:
								if (arguments.code == VKEY::KEY_LEFT) tabOffset = 1;
								else if (arguments.code == VKEY::KEY_RIGHT) tabOffset = -1;
								break;
							case TabPageOrder::TopToBottom:
								if (arguments.code == VKEY::KEY_UP) tabOffset = -1;
								else if (arguments.code == VKEY::KEY_DOWN) tabOffset = 1;
								break;
							case TabPageOrder::BottomToTop:
								if (arguments.code == VKEY::KEY_UP) tabOffset = 1;
								else if (arguments.code == VKEY::KEY_DOWN) tabOffset = -1;
								break;
							default:;
							}

							if (tabOffset != 0)
							{
								arguments.handled = true;
								index += tabOffset;
								if (index < 0) index = 0;
								else if (index >= tabPages.Count()) index = tabPages.Count() - 1;

								SetSelectedPage(tabPages[index]);
							}
						}
					}
				}
			}

			GuiTab::GuiTab(theme::ThemeName themeName)
				:GuiControl(themeName)
				, tabPages(this)
			{
				commandExecutor = Ptr(new CommandExecutor(this));
				SetFocusableComposition(boundsComposition);

				boundsComposition->GetEventReceiver()->keyDown.AttachMethod(this, &GuiTab::OnKeyDown);
			}

			GuiTab::~GuiTab()
			{
			}

			collections::ObservableList<GuiTabPage*>& GuiTab::GetPages()
			{
				return tabPages;
			}

			GuiTabPage* GuiTab::GetSelectedPage()
			{
				return selectedPage;
			}

			bool GuiTab::SetSelectedPage(GuiTabPage* value)
			{
				if (!value)
				{
					if (tabPages.Count() == 0)
					{
						selectedPage = nullptr;
					}
				}
				else if (value->GetOwnerTab() == this)
				{
					if (selectedPage == value)
					{
						return true;
					}

					selectedPage = value;
					for (auto tabPage : tabPages)
					{
						tabPage->SetVisible(tabPage == selectedPage);
					}
				}
				if (auto ct = TypedControlTemplateObject(false))
				{
					ct->SetSelectedTabPage(selectedPage);
				}
				SelectedPageChanged.Execute(GetNotifyEventArguments());
				return selectedPage == value;
			}

/***********************************************************************
GuiScrollView
***********************************************************************/

			void GuiScrollView::BeforeControlTemplateUninstalled_()
			{
				auto ct = TypedControlTemplateObject(false);
				if (!ct) return;

				if (auto scroll = ct->GetHorizontalScroll())
				{
					scroll->PositionChanged.Detach(hScrollHandler);
				}
				if (auto scroll = ct->GetVerticalScroll())
				{
					scroll->PositionChanged.Detach(vScrollHandler);
				}
				ct->GetEventReceiver()->horizontalWheel.Detach(hWheelHandler);
				ct->GetEventReceiver()->verticalWheel.Detach(vWheelHandler);
				ct->CachedBoundsChanged.Detach(containerCachedBoundsChangedHandler);

				hScrollHandler = nullptr;
				vScrollHandler = nullptr;
				hWheelHandler = nullptr;
				vWheelHandler = nullptr;
				containerCachedBoundsChangedHandler = nullptr;
				supressScrolling = false;
			}

			void GuiScrollView::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				if (auto scroll = ct->GetHorizontalScroll())
				{
					hScrollHandler = scroll->PositionChanged.AttachMethod(this, &GuiScrollView::OnHorizontalScroll);
				}
				if (auto scroll = ct->GetVerticalScroll())
				{
					vScrollHandler = scroll->PositionChanged.AttachMethod(this, &GuiScrollView::OnVerticalScroll);
				}
				hWheelHandler = ct->GetEventReceiver()->horizontalWheel.AttachMethod(this, &GuiScrollView::OnHorizontalWheel);
				vWheelHandler = ct->GetEventReceiver()->verticalWheel.AttachMethod(this, &GuiScrollView::OnVerticalWheel);
				containerCachedBoundsChangedHandler = ct->CachedBoundsChanged.AttachMethod(this, &GuiScrollView::OnContainerCachedBoundsChanged);
				CalculateView();
			}

			void GuiScrollView::UpdateDisplayFont()
			{
				GuiControl::UpdateDisplayFont();
				CalculateView();
			}

			void GuiScrollView::OnContainerCachedBoundsChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				CalculateView();
			}

			void GuiScrollView::OnHorizontalScroll(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if(!supressScrolling)
				{
					CallUpdateView();
				}
			}

			void GuiScrollView::OnVerticalScroll(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if(!supressScrolling)
				{
					CallUpdateView();
				}
			}

			void GuiScrollView::OnHorizontalWheel(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
			{
				if(!supressScrolling)
				{
					if (auto scroll = TypedControlTemplateObject(true)->GetHorizontalScroll())
					{
						if (scroll->GetEnabled())
						{
							vint position = scroll->GetPosition();
							vint move = scroll->GetSmallMove();
							position = move * arguments.wheel / 60;
							scroll->SetPosition(position);
						}
					}
				}
			}

			void GuiScrollView::OnVerticalWheel(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
			{
				if(!supressScrolling && GetVisuallyEnabled())
				{
					if (auto scroll = TypedControlTemplateObject(true)->GetVerticalScroll())
					{
						if (scroll->GetEnabled())
						{
							vint position = scroll->GetPosition();
							vint move = scroll->GetSmallMove();
							position -= move * arguments.wheel / 60;
							scroll->SetPosition(position);
						}
					}
				}
			}

			void GuiScrollView::CallUpdateView()
			{
				Rect viewBounds=GetViewBounds();
				UpdateView(viewBounds);
			}

			bool GuiScrollView::AdjustView(Size fullSize)
			{
				auto ct = TypedControlTemplateObject(true);
				auto hScroll = ct->GetHorizontalScroll();
				auto vScroll = ct->GetVerticalScroll();
				Size viewSize = ct->GetContainerComposition()->GetCachedBounds().GetSize();

				auto hVisible = hScroll ? hScroll->GetVisible() : false;
				auto vVisible = vScroll ? vScroll->GetVisible() : false;

				if (hScroll)
				{
					if (fullSize.x <= viewSize.x)
					{
						hScroll->SetVisible(horizontalAlwaysVisible);
						hScroll->SetEnabled(false);
						hScroll->SetPosition(0);
					}
					else
					{
						hScroll->SetVisible(true);
						hScroll->SetEnabled(true);
						hScroll->SetTotalSize(fullSize.x);
						hScroll->SetPageSize(viewSize.x);
					}
				}

				if (vScroll)
				{
					if (fullSize.y <= viewSize.y)
					{
						vScroll->SetVisible(verticalAlwaysVisible);
						vScroll->SetEnabled(false);
						vScroll->SetPosition(0);
					}
					else
					{
						vScroll->SetVisible(true);
						vScroll->SetEnabled(true);
						vScroll->SetTotalSize(fullSize.y);
						vScroll->SetPageSize(viewSize.y);
					}
				}

				auto hVisible2 = hScroll ? hScroll->GetVisible() : false;
				auto vVisible2 = vScroll ? vScroll->GetVisible() : false;
				return hVisible != hVisible2 || vVisible != vVisible2;
			}

			GuiScrollView::GuiScrollView(theme::ThemeName themeName)
				:GuiControl(themeName)
			{
				containerComposition->CachedBoundsChanged.AttachMethod(this, &GuiScrollView::OnContainerCachedBoundsChanged);
			}

			vint GuiScrollView::GetSmallMove()
			{
				return GetDisplayFont().size * 2;
			}

			Size GuiScrollView::GetBigMove()
			{
				return GetViewSize();
			}
			
			GuiScrollView::~GuiScrollView()
			{
			}

			void GuiScrollView::CalculateView()
			{
				TryDelayExecuteIfNotDeleted([=, this]()
				{
					auto ct = TypedControlTemplateObject(true);
					auto hScroll = ct->GetHorizontalScroll();
					auto vScroll = ct->GetVerticalScroll();

					if (!supressScrolling)
					{
						Size fullSize = QueryFullSize();
						while (true)
						{
							bool flagA = false;
							bool flagB = false;

							flagA = AdjustView(fullSize);
							bool bothInvisible = (hScroll ? !hScroll->GetVisible() : true) && (vScroll ? !vScroll->GetVisible() : true);

							if (!bothInvisible)
							{
								flagB = AdjustView(fullSize);
								bothInvisible = (hScroll ? !hScroll->GetVisible() : true) && (vScroll ? !vScroll->GetVisible() : true);
							}

							supressScrolling = true;
							CallUpdateView();
							supressScrolling = false;

							Size newSize = QueryFullSize();
							if (fullSize == newSize)
							{
								vint smallMove = GetSmallMove();
								Size bigMove = GetBigMove();
								if (hScroll)
								{
									hScroll->SetSmallMove(smallMove);
									hScroll->SetBigMove(bigMove.x);
								}
								if (vScroll)
								{
									vScroll->SetSmallMove(smallMove);
									vScroll->SetBigMove(bigMove.y);
								}

								if (bothInvisible || !flagA && !flagB)
								{
									break;
								}
							}
							else
							{
								fullSize = newSize;
							}
						}
					}
				});
			}

			Size GuiScrollView::GetViewSize()
			{
				Size viewSize = TypedControlTemplateObject(true)->GetContainerComposition()->GetCachedBounds().GetSize();
				return viewSize;
			}

			Rect GuiScrollView::GetViewBounds()
			{
				return Rect(GetViewPosition(), GetViewSize());
			}

			Point GuiScrollView::GetViewPosition()
			{
				auto ct = TypedControlTemplateObject(true);
				auto hScroll = ct->GetHorizontalScroll();
				auto vScroll = ct->GetVerticalScroll();
				return Point(
					(hScroll && hScroll->GetEnabled()) ? hScroll->GetPosition() : 0,
					(vScroll && vScroll->GetEnabled()) ? vScroll->GetPosition() : 0
					);
			}

			void GuiScrollView::SetViewPosition(Point value)
			{
				if (GetViewPosition() == value) return;
				auto ct = TypedControlTemplateObject(true);
				if (auto hScroll = ct->GetHorizontalScroll())
				{
					hScroll->SetPosition(value.x);
				}
				if (auto vScroll = ct->GetVerticalScroll())
				{
					vScroll->SetPosition(value.y);
				}
			}

			GuiScroll* GuiScrollView::GetHorizontalScroll()
			{
				return TypedControlTemplateObject(true)->GetHorizontalScroll();
			}

			GuiScroll* GuiScrollView::GetVerticalScroll()
			{
				return TypedControlTemplateObject(true)->GetVerticalScroll();
			}

			bool GuiScrollView::GetHorizontalAlwaysVisible()
			{
				return horizontalAlwaysVisible;
			}

			void GuiScrollView::SetHorizontalAlwaysVisible(bool value)
			{
				if (horizontalAlwaysVisible != value)
				{
					horizontalAlwaysVisible = value;
					CalculateView();
				}
			}

			bool GuiScrollView::GetVerticalAlwaysVisible()
			{
				return verticalAlwaysVisible;
			}

			void GuiScrollView::SetVerticalAlwaysVisible(bool value)
			{
				if (verticalAlwaysVisible != value)
				{
					verticalAlwaysVisible = value;
					CalculateView();
				}
			}

/***********************************************************************
GuiScrollContainer
***********************************************************************/

			Size GuiScrollContainer::QueryFullSize()
			{
				return containerComposition->GetCachedBounds().GetSize();
			}

			void GuiScrollContainer::UpdateView(Rect viewBounds)
			{
				auto leftTop = Point(-viewBounds.x1, -viewBounds.y1);
				containerComposition->SetExpectedBounds(Rect(leftTop, Size(0, 0)));
			}

			GuiScrollContainer::GuiScrollContainer(theme::ThemeName themeName)
				:GuiScrollView(themeName)
			{
				containerComposition->SetAlignmentToParent(Margin(-1, -1, -1, -1));
				UpdateView(Rect(0, 0, 0, 0));
			}

			GuiScrollContainer::~GuiScrollContainer()
			{
			}

			bool GuiScrollContainer::GetExtendToFullWidth()
			{
				return extendToFullWidth;
			}

			void GuiScrollContainer::SetExtendToFullWidth(bool value)
			{
				if (extendToFullWidth != value)
				{
					extendToFullWidth = value;
					auto margin = containerComposition->GetAlignmentToParent();
					if (value)
					{
						containerComposition->SetAlignmentToParent(Margin(0, margin.top, 0, margin.bottom));
					}
					else
					{
						containerComposition->SetAlignmentToParent(Margin(-1, margin.top, -1, margin.bottom));
					}
				}
			}

			bool GuiScrollContainer::GetExtendToFullHeight()
			{
				return extendToFullHeight;
			}

			void GuiScrollContainer::SetExtendToFullHeight(bool value)
			{
				if (extendToFullHeight != value)
				{
					extendToFullHeight = value;
					auto margin = containerComposition->GetAlignmentToParent();
					if (value)
					{
						containerComposition->SetAlignmentToParent(Margin(margin.left, 0, margin.right, 0));
					}
					else
					{
						containerComposition->SetAlignmentToParent(Margin(margin.left, -1, margin.right, -1));
					}
				}
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\GUIDATETIMECONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace collections;
			using namespace compositions;
			using namespace elements;

/***********************************************************************
GuiDatePicker::CommandExecutor
***********************************************************************/

			GuiDatePicker::CommandExecutor::CommandExecutor(GuiDatePicker* _datePicker)
				:datePicker(_datePicker)
			{
			}

			GuiDatePicker::CommandExecutor::~CommandExecutor()
			{
			}

			void GuiDatePicker::CommandExecutor::NotifyDateChanged()
			{
				datePicker->date = datePicker->TypedControlTemplateObject(true)->GetDate();
				datePicker->UpdateText();
				datePicker->DateChanged.Execute(datePicker->GetNotifyEventArguments());
			}

			void GuiDatePicker::CommandExecutor::NotifyDateNavigated()
			{
				datePicker->DateNavigated.Execute(datePicker->GetNotifyEventArguments());
			}

			void GuiDatePicker::CommandExecutor::NotifyDateSelected()
			{
				datePicker->DateSelected.Execute(datePicker->GetNotifyEventArguments());
			}

/***********************************************************************
GuiDatePicker
***********************************************************************/

			void GuiDatePicker::BeforeControlTemplateUninstalled_()
			{
				auto ct = TypedControlTemplateObject(false);
				if (!ct) return;

				ct->SetCommands(nullptr);
			}

			void GuiDatePicker::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				ct->SetCommands(commandExecutor.Obj());
				ct->SetDate(date);
				ct->SetDateLocale(dateLocale);
				UpdateText();
			}

			void GuiDatePicker::UpdateText()
			{
				GuiControl::SetText(dateLocale.FormatDate(dateFormat, date));
			}

			bool GuiDatePicker::IsAltAvailable()
			{
				if (nestedAlt)
				{
					return alt != L"";
				}
				else
				{
					return GuiControl::IsAltAvailable();
				}
			}

			compositions::IGuiAltActionHost* GuiDatePicker::GetActivatingAltHost()
			{
				if (nestedAlt)
				{
					return this;
				}
				else
				{
					return GuiControl::GetActivatingAltHost();
				}
			}

			GuiDatePicker::GuiDatePicker(theme::ThemeName themeName, bool _nestedAlt)
				:GuiControl(themeName)
				, nestedAlt(_nestedAlt)
			{
				commandExecutor = Ptr(new CommandExecutor(this));
				SetDate(DateTime::LocalTime());
				SetDateLocale(Locale::UserDefault());
				SetAltComposition(boundsComposition);
				SetAltControl(this, false);

				DateChanged.SetAssociatedComposition(boundsComposition);
				DateNavigated.SetAssociatedComposition(boundsComposition);
				DateSelected.SetAssociatedComposition(boundsComposition);
				DateFormatChanged.SetAssociatedComposition(boundsComposition);
				DateLocaleChanged.SetAssociatedComposition(boundsComposition);

				commandExecutor->NotifyDateChanged();
			}

			GuiDatePicker::~GuiDatePicker()
			{
			}

			const DateTime& GuiDatePicker::GetDate()
			{
				return date;
			}

			void GuiDatePicker::SetDate(const DateTime& value)
			{
				if (date != value)
				{
					date = value;
					TypedControlTemplateObject(true)->SetDate(value);
				}
			}

			const WString& GuiDatePicker::GetDateFormat()
			{
				return dateFormat;
			}

			void GuiDatePicker::SetDateFormat(const WString& value)
			{
				dateFormat=value;
				UpdateText();
				DateFormatChanged.Execute(GetNotifyEventArguments());
			}

			const Locale& GuiDatePicker::GetDateLocale()
			{
				return dateLocale;
			}

			void GuiDatePicker::SetDateLocale(const Locale& value)
			{
				dateLocale=value;
				List<WString> formats;
				dateLocale.GetLongDateFormats(formats);
				if(formats.Count()>0)
				{
					dateFormat=formats[0];
				}
				TypedControlTemplateObject(true)->SetDateLocale(dateLocale);

				UpdateText();
				DateFormatChanged.Execute(GetNotifyEventArguments());
				DateLocaleChanged.Execute(GetNotifyEventArguments());
			}

			void GuiDatePicker::SetText(const WString& value)
			{
			}

/***********************************************************************
GuiDateComboBox
***********************************************************************/

			void GuiDateComboBox::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiDateComboBox::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				datePicker->SetControlTemplate(ct->GetDatePickerTemplate());
			}

			void GuiDateComboBox::UpdateText()
			{
				SetText(datePicker->GetDateLocale().FormatDate(datePicker->GetDateFormat(), selectedDate));
			}

			void GuiDateComboBox::NotifyUpdateSelectedDate()
			{
				UpdateText();
				SelectedDateChanged.Execute(GetNotifyEventArguments());
			}

			void GuiDateComboBox::OnSubMenuOpeningChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				datePicker->SetDate(selectedDate);
			}

			void GuiDateComboBox::datePicker_DateLocaleChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				UpdateText();
			}

			void GuiDateComboBox::datePicker_DateFormatChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				UpdateText();
			}

			void GuiDateComboBox::datePicker_DateSelected(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				selectedDate=datePicker->GetDate();
				GetSubMenu()->Hide();
				NotifyUpdateSelectedDate();
			}

			GuiDateComboBox::GuiDateComboBox(theme::ThemeName themeName)
				:GuiComboBoxBase(themeName, true)
			{
				SelectedDateChanged.SetAssociatedComposition(GetBoundsComposition());
				
				datePicker = new GuiDatePicker(theme::ThemeName::DatePicker, false);
				datePicker->DateSelected.AttachMethod(this, &GuiDateComboBox::datePicker_DateSelected);
				datePicker->DateLocaleChanged.AttachMethod(this, &GuiDateComboBox::datePicker_DateLocaleChanged);
				datePicker->DateFormatChanged.AttachMethod(this, &GuiDateComboBox::datePicker_DateFormatChanged);
				datePicker->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));

				GetSubMenu()->GetContainerComposition()->AddChild(datePicker->GetBoundsComposition());
				GetSubMenu()->SetHideOnDeactivateAltHost(false);

				selectedDate=datePicker->GetDate();
				SubMenuOpeningChanged.AttachMethod(this, &GuiDateComboBox::OnSubMenuOpeningChanged);
				SetFont(GetFont());
				SetText(datePicker->GetText());
			}

			GuiDateComboBox::~GuiDateComboBox()
			{
			}

			void GuiDateComboBox::SetFont(const Nullable<FontProperties>& value)
			{
				GuiComboBoxBase::SetFont(value);
				datePicker->SetFont(value);
			}

			const DateTime& GuiDateComboBox::GetSelectedDate()
			{
				return selectedDate;
			}

			void GuiDateComboBox::SetSelectedDate(const DateTime& value)
			{
				selectedDate=value;
				datePicker->SetDate(selectedDate);
				NotifyUpdateSelectedDate();
			}

			GuiDatePicker* GuiDateComboBox::GetDatePicker()
			{
				return datePicker;
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\GUIDIALOGS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace elements;
			using namespace compositions;
			using namespace collections;
			using namespace reflection::description;

/***********************************************************************
GuiDialogBase
***********************************************************************/

			GuiWindow* GuiDialogBase::GetHostWindow()
			{
				if (rootObject)
				{
					if (auto control = dynamic_cast<GuiControl*>(rootObject))
					{
						if (auto host = control->GetRelatedControlHost())
						{
							return dynamic_cast<GuiWindow*>(host);
						}
					}
					else if (auto composition = dynamic_cast<GuiGraphicsComposition*>(rootObject))
					{
						if (auto host = composition->GetRelatedControlHost())
						{
							return dynamic_cast<GuiWindow*>(host);
						}
					}
				}
				return nullptr;
			}

			GuiDialogBase::GuiDialogBase()
			{
			}

			GuiDialogBase::~GuiDialogBase()
			{
			}

			void GuiDialogBase::Attach(GuiInstanceRootObject* _rootObject)
			{
				rootObject = _rootObject;
			}

			void GuiDialogBase::Detach(GuiInstanceRootObject* _rootObject)
			{
				rootObject = nullptr;
			}

/***********************************************************************
GuiMessageDialog
***********************************************************************/

			GuiMessageDialog::GuiMessageDialog()
			{
			}

			GuiMessageDialog::~GuiMessageDialog()
			{
			}

			INativeDialogService::MessageBoxButtonsInput GuiMessageDialog::GetInput()
			{
				return input;
			}

			void GuiMessageDialog::SetInput(INativeDialogService::MessageBoxButtonsInput value)
			{
				input = value;
			}

			INativeDialogService::MessageBoxDefaultButton GuiMessageDialog::GetDefaultButton()
			{
				return defaultButton;
			}

			void GuiMessageDialog::SetDefaultButton(INativeDialogService::MessageBoxDefaultButton value)
			{
				defaultButton = value;
			}

			INativeDialogService::MessageBoxIcons GuiMessageDialog::GetIcon()
			{
				return icon;
			}

			void GuiMessageDialog::SetIcon(INativeDialogService::MessageBoxIcons value)
			{
				icon = value;
			}

			INativeDialogService::MessageBoxModalOptions GuiMessageDialog::GetModalOption()
			{
				return modalOption;
			}

			void GuiMessageDialog::SetModalOption(INativeDialogService::MessageBoxModalOptions value)
			{
				modalOption = value;
			}

			const WString& GuiMessageDialog::GetText()
			{
				return text;
			}

			void GuiMessageDialog::SetText(const WString& value)
			{
				text = value;
			}

			const WString& GuiMessageDialog::GetTitle()
			{
				return title;
			}

			void GuiMessageDialog::SetTitle(const WString& value)
			{
				title = value;
			}

			INativeDialogService::MessageBoxButtonsOutput GuiMessageDialog::ShowDialog()
			{
				auto service = GetCurrentController()->DialogService();
				return service->ShowMessageBox(GetHostWindow()->GetNativeWindow(), text, title, input, defaultButton, icon, modalOption);
			}

/***********************************************************************
GuiColorDialog
***********************************************************************/

			GuiColorDialog::GuiColorDialog()
			{
				for (vint i = 0; i < 16; i++)
				{
					customColors.Add(Color());
				}
			}

			GuiColorDialog::~GuiColorDialog()
			{
			}

			bool GuiColorDialog::GetEnabledCustomColor()
			{
				return enabledCustomColor;
			}

			void GuiColorDialog::SetEnabledCustomColor(bool value)
			{
				enabledCustomColor = value;
			}

			bool GuiColorDialog::GetOpenedCustomColor()
			{
				return openedCustomColor;
			}

			void GuiColorDialog::SetOpenedCustomColor(bool value)
			{
				openedCustomColor = value;
			}

			Color GuiColorDialog::GetSelectedColor()
			{
				return selectedColor;
			}

			void GuiColorDialog::SetSelectedColor(Color value)
			{
				if (selectedColor != value)
				{
					selectedColor = value;
					SelectedColorChanged.Execute(GuiEventArgs());
				}
			}

			collections::List<Color>& GuiColorDialog::GetCustomColors()
			{
				return customColors;
			}

			bool GuiColorDialog::ShowDialog()
			{
				Array<Color> colors;
				CopyFrom(colors, customColors);
				colors.Resize(16);

				INativeDialogService::ColorDialogCustomColorOptions options =
					!enabledCustomColor ? INativeDialogService::CustomColorDisabled :
					!openedCustomColor ? INativeDialogService::CustomColorEnabled :
					INativeDialogService::CustomColorOpened;

				auto service = GetCurrentController()->DialogService();
				if (!service->ShowColorDialog(GetHostWindow()->GetNativeWindow(), selectedColor, showSelection, options, &colors[0]))
				{
					return false;
				}

				CopyFrom(customColors, colors);
				SelectedColorChanged.Execute(GuiEventArgs());
				return true;
			}

/***********************************************************************
GuiFontDialog
***********************************************************************/

			GuiFontDialog::GuiFontDialog()
			{
			}

			GuiFontDialog::~GuiFontDialog()
			{
			}

			const FontProperties& GuiFontDialog::GetSelectedFont()
			{
				return selectedFont;
			}

			void GuiFontDialog::SetSelectedFont(const FontProperties& value)
			{
				if (selectedFont != value)
				{
					selectedFont = value;
					SelectedFontChanged.Execute(GuiEventArgs());
				}
			}

			Color GuiFontDialog::GetSelectedColor()
			{
				return selectedColor;
			}

			void GuiFontDialog::SetSelectedColor(Color value)
			{
				if (selectedColor != value)
				{
					selectedColor = value;
					SelectedColorChanged.Execute(GuiEventArgs());
				}
			}

			bool GuiFontDialog::GetShowSelection()
			{
				return showSelection;
			}

			void GuiFontDialog::SetShowSelection(bool value)
			{
				showSelection = value;
			}

			bool GuiFontDialog::GetShowEffect()
			{
				return showEffect;
			}

			void GuiFontDialog::SetShowEffect(bool value)
			{
				showEffect = value;
			}

			bool GuiFontDialog::GetForceFontExist()
			{
				return forceFontExist;
			}

			void GuiFontDialog::SetForceFontExist(bool value)
			{
				forceFontExist = value;
			}

			bool GuiFontDialog::ShowDialog()
			{
				auto service = GetCurrentController()->DialogService();
				if (!service->ShowFontDialog(GetHostWindow()->GetNativeWindow(), selectedFont, selectedColor, showSelection, showEffect, forceFontExist))
				{
					return false;
				}

				SelectedColorChanged.Execute(GuiEventArgs());
				SelectedFontChanged.Execute(GuiEventArgs());
				return true;
			}

/***********************************************************************
GuiFileDialogBase
***********************************************************************/

			GuiFileDialogBase::GuiFileDialogBase()
			{
			}

			GuiFileDialogBase::~GuiFileDialogBase()
			{
			}

			const WString& GuiFileDialogBase::GetFilter()
			{
				return filter;
			}

			void GuiFileDialogBase::SetFilter(const WString& value)
			{
				filter = value;
			}

			vint GuiFileDialogBase::GetFilterIndex()
			{
				return filterIndex;
			}

			void GuiFileDialogBase::SetFilterIndex(vint value)
			{
				if (filterIndex != value)
				{
					filterIndex = value;
					FilterIndexChanged.Execute(GuiEventArgs());
				}
			}

			bool GuiFileDialogBase::GetEnabledPreview()
			{
				return enabledPreview;
			}

			void GuiFileDialogBase::SetEnabledPreview(bool value)
			{
				enabledPreview = value;
			}

			WString GuiFileDialogBase::GetTitle()
			{
				return title;
			}

			void GuiFileDialogBase::SetTitle(const WString& value)
			{
				title = value;
			}

			WString GuiFileDialogBase::GetFileName()
			{
				return fileName;
			}

			void GuiFileDialogBase::SetFileName(const WString& value)
			{
				if (fileName != value)
				{
					fileName = value;
					FileNameChanged.Execute(GuiEventArgs());
				}
			}

			WString GuiFileDialogBase::GetDirectory()
			{
				return directory;
			}

			void GuiFileDialogBase::SetDirectory(const WString& value)
			{
				directory = value;
			}

			WString GuiFileDialogBase::GetDefaultExtension()
			{
				return defaultExtension;
			}

			void GuiFileDialogBase::SetDefaultExtension(const WString& value)
			{
				defaultExtension = value;
			}

			INativeDialogService::FileDialogOptions GuiFileDialogBase::GetOptions()
			{
				return options;
			}

			void GuiFileDialogBase::SetOptions(INativeDialogService::FileDialogOptions value)
			{
				options = value;
			}

/***********************************************************************
GuiOpenFileDialog
***********************************************************************/

			GuiOpenFileDialog::GuiOpenFileDialog()
			{
			}

			GuiOpenFileDialog::~GuiOpenFileDialog()
			{
			}

			collections::List<WString>& GuiOpenFileDialog::GetFileNames()
			{
				return fileNames;
			}

			bool GuiOpenFileDialog::ShowDialog()
			{
				fileNames.Clear();
				auto service = GetCurrentController()->DialogService();
				if (!service->ShowFileDialog(
					GetHostWindow()->GetNativeWindow(),
					fileNames,
					filterIndex,
					(enabledPreview ? INativeDialogService::FileDialogOpenPreview : INativeDialogService::FileDialogOpen),
					title,
					fileName,
					directory,
					defaultExtension,
					filter,
					options))
				{
					return false;
				}

				if (fileNames.Count() > 0)
				{
					fileName = fileNames[0];
					FileNameChanged.Execute(GuiEventArgs());
					FilterIndexChanged.Execute(GuiEventArgs());
				}
				return true;
			}

/***********************************************************************
GuiSaveFileDialog
***********************************************************************/

			GuiSaveFileDialog::GuiSaveFileDialog()
			{
			}

			GuiSaveFileDialog::~GuiSaveFileDialog()
			{
			}

			bool GuiSaveFileDialog::ShowDialog()
			{
				List<WString> fileNames;
				auto service = GetCurrentController()->DialogService();
				if (!service->ShowFileDialog(
					GetHostWindow()->GetNativeWindow(),
					fileNames,
					filterIndex,
					(enabledPreview ? INativeDialogService::FileDialogSavePreview : INativeDialogService::FileDialogSave),
					title,
					fileName,
					directory,
					defaultExtension,
					filter,
					options))
				{
					return false;
				}

				if (fileNames.Count() > 0)
				{
					fileName = fileNames[0];
					FileNameChanged.Execute(GuiEventArgs());
					FilterIndexChanged.Execute(GuiEventArgs());
				}
				return true;
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\GUISCROLLCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace elements;
			using namespace compositions;
			using namespace collections;
			using namespace reflection::description;

/***********************************************************************
GuiScroll::CommandExecutor
***********************************************************************/

			GuiScroll::CommandExecutor::CommandExecutor(GuiScroll* _scroll)
				:scroll(_scroll)
			{
			}

			GuiScroll::CommandExecutor::~CommandExecutor()
			{
			}

			void GuiScroll::CommandExecutor::SmallDecrease()
			{
				scroll->SetPosition(scroll->GetPosition()-scroll->GetSmallMove());
			}

			void GuiScroll::CommandExecutor::SmallIncrease()
			{
				scroll->SetPosition(scroll->GetPosition()+scroll->GetSmallMove());
			}

			void GuiScroll::CommandExecutor::BigDecrease()
			{
				scroll->SetPosition(scroll->GetPosition()-scroll->GetBigMove());
			}

			void GuiScroll::CommandExecutor::BigIncrease()
			{
				scroll->SetPosition(scroll->GetPosition()+scroll->GetBigMove());
			}
			
			void GuiScroll::CommandExecutor::SetTotalSize(vint value)
			{
				scroll->SetTotalSize(value);
			}

			void GuiScroll::CommandExecutor::SetPageSize(vint value)
			{
				scroll->SetPageSize(value);
			}

			void GuiScroll::CommandExecutor::SetPosition(vint value)
			{
				scroll->SetPosition(value);
			}

/***********************************************************************
GuiScroll
***********************************************************************/

			void GuiScroll::OnActiveAlt()
			{
				if (autoFocus)
				{
					GuiControl::OnActiveAlt();
				}
			}

			bool GuiScroll::IsTabAvailable()
			{
				return autoFocus && GuiControl::IsTabAvailable();
			}

			void GuiScroll::OnKeyDown(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
				if (arguments.eventSource == focusableComposition)
				{
					switch (arguments.code)
					{
					case VKEY::KEY_HOME:
						SetPosition(GetMinPosition());
						arguments.handled = true;
						break;
					case VKEY::KEY_END:
						SetPosition(GetMaxPosition());
						arguments.handled = true;
						break;
					case VKEY::KEY_PRIOR:
						commandExecutor->BigDecrease();
						arguments.handled = true;
						break;
					case VKEY::KEY_NEXT:
						commandExecutor->BigIncrease();
						arguments.handled = true;
						break;
					case VKEY::KEY_LEFT:
					case VKEY::KEY_UP:
						commandExecutor->SmallDecrease();
						arguments.handled = true;
						break;
					case VKEY::KEY_RIGHT:
					case VKEY::KEY_DOWN:
						commandExecutor->SmallIncrease();
						arguments.handled = true;
						break;
					default:;
					}
				}
			}

			void GuiScroll::OnMouseDown(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
			{
				if (autoFocus)
				{
					SetFocused();
				}
			}

			void GuiScroll::BeforeControlTemplateUninstalled_()
			{
				auto ct = TypedControlTemplateObject(false);
				if (!ct) return;

				ct->SetCommands(nullptr);
			}

			void GuiScroll::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				ct->SetCommands(commandExecutor.Obj());
				ct->SetPageSize(pageSize);
				ct->SetTotalSize(totalSize);
				ct->SetPosition(position);
			}

			GuiScroll::GuiScroll(theme::ThemeName themeName)
				:GuiControl(themeName)
			{
				if (themeName == theme::ThemeName::ProgressBar)
				{
					autoFocus = false;
				}
				else
				{
					SetFocusableComposition(boundsComposition);
				}

				TotalSizeChanged.SetAssociatedComposition(boundsComposition);
				PageSizeChanged.SetAssociatedComposition(boundsComposition);
				PositionChanged.SetAssociatedComposition(boundsComposition);
				SmallMoveChanged.SetAssociatedComposition(boundsComposition);
				BigMoveChanged.SetAssociatedComposition(boundsComposition);

				commandExecutor = Ptr(new CommandExecutor(this));
				boundsComposition->GetEventReceiver()->keyDown.AttachMethod(this, &GuiScroll::OnKeyDown);
				boundsComposition->GetEventReceiver()->leftButtonDown.AttachMethod(this, &GuiScroll::OnMouseDown);
				boundsComposition->GetEventReceiver()->rightButtonDown.AttachMethod(this, &GuiScroll::OnMouseDown);
			}

			GuiScroll::~GuiScroll()
			{
			}

			vint GuiScroll::GetTotalSize()
			{
				return totalSize;
			}

			void GuiScroll::SetTotalSize(vint value)
			{
				if(totalSize!=value && 0<value)
				{
					totalSize=value;
					if(pageSize>totalSize)
					{
						SetPageSize(totalSize);
					}
					if(position>GetMaxPosition())
					{
						SetPosition(GetMaxPosition());
					}
					TypedControlTemplateObject(true)->SetTotalSize(totalSize);
					TotalSizeChanged.Execute(GetNotifyEventArguments());
				}
			}

			vint GuiScroll::GetPageSize()
			{
				return pageSize;
			}

			void GuiScroll::SetPageSize(vint value)
			{
				if(pageSize!=value && 0<=value && value<=totalSize)
				{
					pageSize=value;
					if(position>GetMaxPosition())
					{
						SetPosition(GetMaxPosition());
					}
					TypedControlTemplateObject(true)->SetPageSize(pageSize);
					PageSizeChanged.Execute(GetNotifyEventArguments());
				}
			}

			vint GuiScroll::GetPosition()
			{
				return position;
			}

			void GuiScroll::SetPosition(vint value)
			{
				vint min=GetMinPosition();
				vint max=GetMaxPosition();
				vint newPosition=
					value<min?min:
					value>max?max:
					value;
				if(position!=newPosition)
				{
					position=newPosition;
					TypedControlTemplateObject(true)->SetPosition(position);
					PositionChanged.Execute(GetNotifyEventArguments());
				}
			}

			vint GuiScroll::GetSmallMove()
			{
				return smallMove;
			}

			void GuiScroll::SetSmallMove(vint value)
			{
				if(value>0 && smallMove!=value)
				{
					smallMove=value;
					SmallMoveChanged.Execute(GetNotifyEventArguments());
				}
			}

			vint GuiScroll::GetBigMove()
			{
				return bigMove;
			}

			void GuiScroll::SetBigMove(vint value)
			{
				if(value>0 && bigMove!=value)
				{
					bigMove=value;
					BigMoveChanged.Execute(GetNotifyEventArguments());
				}
			}

			vint GuiScroll::GetMinPosition()
			{
				return 0;
			}

			vint GuiScroll::GetMaxPosition()
			{
				return totalSize-pageSize;
			}

			bool GuiScroll::GetAutoFocus()
			{
				return autoFocus;
			}

			void GuiScroll::SetAutoFocus(bool value)
			{
				autoFocus = value;
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\DATASOURCEIMPL_IITEMPROVIDER_ITEMPROVIDERBASE.CPP
***********************************************************************/

namespace vl::presentation::controls::list
{
/***********************************************************************
ItemProviderBase
***********************************************************************/

	void ItemProviderBase::InvokeOnItemModified(vint start, vint count, vint newCount, bool itemReferenceUpdated)
	{
		CHECK_ERROR(!callingOnItemModified, L"ItemProviderBase::InvokeOnItemModified(vint, vint, vint)#Canning modify the observable data source during its item modified event, which will cause this event to be executed recursively.");
		callingOnItemModified = true;
		// TODO: (enumerable) foreach
		for (vint i = 0; i < callbacks.Count(); i++)
		{
			callbacks[i]->OnItemModified(start, count, newCount, itemReferenceUpdated);
		}
		callingOnItemModified = false;
	}

	ItemProviderBase::ItemProviderBase()
	{
	}

	ItemProviderBase::~ItemProviderBase()
	{
		// TODO: (enumerable) foreach
		for(vint i=0;i<callbacks.Count();i++)
		{
			callbacks[i]->OnAttached(0);
		}
	}

	bool ItemProviderBase::AttachCallback(IItemProviderCallback* value)
	{
		if(callbacks.Contains(value))
		{
			return false;
		}
		else
		{
			callbacks.Add(value);
			value->OnAttached(this);
			return true;
		}
	}

	bool ItemProviderBase::DetachCallback(IItemProviderCallback* value)
	{
		vint index=callbacks.IndexOf(value);
		if(index==-1)
		{
			return false;
		}
		else
		{
			value->OnAttached(0);
			callbacks.Remove(value);
			return true;
		}
	}

	void ItemProviderBase::PushEditing()
	{
		editingCounter++;
	}

	bool ItemProviderBase::PopEditing()
	{
		if (editingCounter == 0)return false;
		editingCounter--;
		return true;
	}

	bool ItemProviderBase::IsEditing()
	{
		return editingCounter > 0;
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\DATASOURCEIMPL_IITEMPROVIDER_NODEITEMPROVIDER.CPP
***********************************************************************/

namespace vl::presentation::controls::tree
{
	using namespace reflection::description;

	const wchar_t* const INodeItemView::Identifier = L"vl::presentation::controls::tree::INodeItemView";

/***********************************************************************
NodeItemProvider
***********************************************************************/

	Ptr<INodeProvider> NodeItemProvider::GetNodeByOffset(Ptr<INodeProvider> provider, vint offset)
	{
		if (offset == 0) return provider;
		Ptr<INodeProvider> result;
		if (provider->GetExpanding() && offset > 0)
		{
			offset -= 1;
			vint count = provider->GetChildCount();
			for (vint i = 0; (!result && i < count); i++)
			{
				auto child = provider->GetChild(i);
				vint visibleCount = child->CalculateTotalVisibleNodes();
				if (offset < visibleCount)
				{
					result = GetNodeByOffset(child, offset);
				}
				else
				{
					offset -= visibleCount;
				}
			}
		}
		return result;
	}

	void NodeItemProvider::OnAttached(INodeRootProvider* provider)
	{
	}

	void NodeItemProvider::OnBeforeItemModified(INodeProvider* parentNode, vint start, vint count, vint newCount, bool itemReferenceUpdated)
	{
		vint offset = 0;
		vint base = CalculateNodeVisibilityIndexInternal(parentNode);
		if (base != -2 && parentNode->GetExpanding())
		{
			for (vint i = 0; i < count; i++)
			{
				auto child = parentNode->GetChild(start + i);
				offset += child->CalculateTotalVisibleNodes();
			}
		}
		offsetBeforeChildModifieds.Set(parentNode, offset);
	}

	void NodeItemProvider::OnAfterItemModified(INodeProvider* parentNode, vint start, vint count, vint newCount, bool itemReferenceUpdated)
	{
		vint offsetBeforeChildModified = 0;
		{
			vint index = offsetBeforeChildModifieds.Keys().IndexOf(parentNode);
			if (index != -1)
			{
				offsetBeforeChildModified = offsetBeforeChildModifieds.Values().Get(index);
				offsetBeforeChildModifieds.Remove(parentNode);
			}
		}

		vint base = CalculateNodeVisibilityIndexInternal(parentNode);
		if (base != -2 && parentNode->GetExpanding())
		{
			vint offset = 0;
			vint firstChildStart = -1;
			for (vint i = 0; i < newCount; i++)
			{
				auto child = parentNode->GetChild(start + i);
				if (i == 0)
				{
					firstChildStart = CalculateNodeVisibilityIndexInternal(child.Obj());
				}
				offset += child->CalculateTotalVisibleNodes();
			}

			if (firstChildStart == -1)
			{
				vint childCount = parentNode->GetChildCount();
				if (childCount == 0)
				{
					firstChildStart = base + 1;
				}
				else if (start < childCount)
				{
					auto child = parentNode->GetChild(start);
					firstChildStart = CalculateNodeVisibilityIndexInternal(child.Obj());
				}
				else
				{
					auto child = parentNode->GetChild(start - 1);
					firstChildStart = CalculateNodeVisibilityIndexInternal(child.Obj());
					firstChildStart += child->CalculateTotalVisibleNodes();
				}
			}
			InvokeOnItemModified(firstChildStart, offsetBeforeChildModified, offset, itemReferenceUpdated);
		}
	}

	void NodeItemProvider::OnItemExpanded(INodeProvider* node)
	{
		vint base = CalculateNodeVisibilityIndexInternal(node);
		if (base != -2)
		{
			vint visibility = node->CalculateTotalVisibleNodes();
			InvokeOnItemModified(base + 1, 0, visibility - 1, true);
		}
	}

	void NodeItemProvider::OnItemCollapsed(INodeProvider* node)
	{
		vint base = CalculateNodeVisibilityIndexInternal(node);
		if (base != -2)
		{
			vint visibility = 0;
			vint count = node->GetChildCount();
			for (vint i = 0; i < count; i++)
			{
				auto child = node->GetChild(i);
				visibility += child->CalculateTotalVisibleNodes();
			}
			InvokeOnItemModified(base + 1, visibility, 0, true);
		}
	}

	vint NodeItemProvider::CalculateNodeVisibilityIndexInternal(INodeProvider* node)
	{
		auto parent = node->GetParent();
		if (!parent)
		{
			return -1;
		}
		if (!parent->GetExpanding())
		{
			return -2;
		}

		vint index = CalculateNodeVisibilityIndexInternal(parent.Obj());
		if (index == -2)
		{
			return -2;
		}
		if (index == -1)
		{
			// Parent returned -1, which means parent has no parent (is a root node)
			// Check if this parent is OUR root - if not, this is a foreign node
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::tree::NodeItemProvider::CalculateNodeVisibilityIndexInternal(INodeProvider*)#"
			CHECK_ERROR(parent.Obj() == root->GetRootNode().Obj(), ERROR_MESSAGE_PREFIX L"The node does not belong to the tree associated with this NodeItemProvider.");
#undef ERROR_MESSAGE_PREFIX
		}

		vint count = parent->GetChildCount();
		for (vint i = 0; i < count; i++)
		{
			auto child = parent->GetChild(i);
			bool findResult = child == node;
			if (findResult)
			{
				index++;
			}
			else
			{
				index += child->CalculateTotalVisibleNodes();
			}
			if (findResult)
			{
				return index;
			}
		}
		return -1;
	}

	NodeItemProvider::NodeItemProvider(Ptr<INodeRootProvider> _root)
		:root(_root)
	{
		root->AttachCallback(this);
	}

	NodeItemProvider::~NodeItemProvider()
	{
		root->DetachCallback(this);
	}

	Ptr<INodeRootProvider> NodeItemProvider::GetRoot()
	{
		return root;
	}

	Ptr<INodeProvider> NodeItemProvider::RequestNode(vint index)
	{
		if (index < 0 || index >= Count())
		{
			return nullptr;
		}
		else if (root->CanGetNodeByVisibleIndex())
		{
			return root->GetNodeByVisibleIndex(index + 1);
		}
		else
		{
			return GetNodeByOffset(root->GetRootNode(), index + 1);
		}
	}

	vint NodeItemProvider::CalculateNodeVisibilityIndex(INodeProvider* node)
	{
		vint result = CalculateNodeVisibilityIndexInternal(node);
		return result < 0 ? -1 : result;
	}

	vint NodeItemProvider::Count()
	{
		return root->GetRootNode()->CalculateTotalVisibleNodes()-1;
	}

	WString NodeItemProvider::GetTextValue(vint itemIndex)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::tree::NodeItemProvider::GetTextValue(vint)#"
		CHECK_ERROR(0 <= itemIndex && itemIndex < Count(), ERROR_MESSAGE_PREFIX L"Index out of range.");
		auto node = RequestNode(itemIndex);
		return root->GetTextValue(node.Obj());
#undef ERROR_MESSAGE_PREFIX
	}

	description::Value NodeItemProvider::GetBindingValue(vint itemIndex)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::tree::NodeItemProvider::GetBindingValue(vint)#"
		CHECK_ERROR(0 <= itemIndex && itemIndex < Count(), ERROR_MESSAGE_PREFIX L"Index out of range.");
		auto node = RequestNode(itemIndex);
		return root->GetBindingValue(node.Obj());
#undef ERROR_MESSAGE_PREFIX
	}

	IDescriptable* NodeItemProvider::RequestView(const WString& identifier)
	{
		if(identifier==INodeItemView::Identifier)
		{
			return (INodeItemView*)this;
		}
		else
		{
			return root->RequestView(identifier);
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\DATASOURCEIMPL_INODEPROVIDER_MEMORYNODEPROVIDER.CPP
***********************************************************************/

namespace vl::presentation::controls::tree
{
/***********************************************************************
MemoryNodeProvider::NodeCollection
***********************************************************************/

	void MemoryNodeProvider::NodeCollection::OnBeforeChildModified(vint start, vint count, vint newCount)
	{
		if (ownerProvider->expanding)
		{
			for (vint i = 0; i < count; i++)
			{
				offsetBeforeChildModified += items[start + i]->totalVisibleNodeCount;
			}
		}
		INodeProviderCallback* proxy = ownerProvider->GetCallbackProxyInternal();
		if (proxy)
		{
			proxy->OnBeforeItemModified(ownerProvider, start, count, newCount, true);
		}
	}

	void MemoryNodeProvider::NodeCollection::OnAfterChildModified(vint start, vint count, vint newCount)
	{
		ownerProvider->childCount += (newCount - count);
		if (ownerProvider->expanding)
		{
			vint offset = 0;
			for (vint i = 0; i < newCount; i++)
			{
				offset += items[start + i]->totalVisibleNodeCount;
			}
			ownerProvider->OnChildTotalVisibleNodesChanged(offset - offsetBeforeChildModified);
		}
		offsetBeforeChildModified = 0;
		INodeProviderCallback* proxy = ownerProvider->GetCallbackProxyInternal();
		if (proxy)
		{
			proxy->OnAfterItemModified(ownerProvider, start, count, newCount, true);
		}
	}

	bool MemoryNodeProvider::NodeCollection::QueryRemove(vint index, Ptr<MemoryNodeProvider> const& child)
	{
		return child->parent == ownerProvider;
	}

	void MemoryNodeProvider::NodeCollection::BeforeInsert(vint index, Ptr<MemoryNodeProvider> const& child)
	{
		// Check if this node is already in a provider
		if (child->parent)
		{
			throw ArgumentException(
				L"The MemoryNodeProvider is already belong to a parent node.",
				L"vl::presentation::controls::tree::MemoryNodeProvider::NodeCollection::BeforeInsert",
				L"child"
			);
		}
		OnBeforeChildModified(index, 0, 1);
		child->parent = ownerProvider;
	}

	void MemoryNodeProvider::NodeCollection::BeforeRemove(vint index, Ptr<MemoryNodeProvider> const& child)
	{
		OnBeforeChildModified(index, 1, 0);
		child->parent = 0;
	}

	void MemoryNodeProvider::NodeCollection::AfterInsert(vint index, Ptr<MemoryNodeProvider> const& child)
	{
		OnAfterChildModified(index, 0, 1);
	}

	void MemoryNodeProvider::NodeCollection::AfterRemove(vint index, vint count)
	{
		OnAfterChildModified(index, count, 0);
	}

	MemoryNodeProvider::NodeCollection::NodeCollection()
		:ownerProvider(0)
	{
	}

/***********************************************************************
MemoryNodeProvider
***********************************************************************/

	INodeProviderCallback* MemoryNodeProvider::GetCallbackProxyInternal()
	{
		if(parent)
		{
			return parent->GetCallbackProxyInternal();
		}
		else
		{
			return 0;
		}
	}

	void MemoryNodeProvider::OnChildTotalVisibleNodesChanged(vint offset)
	{
		totalVisibleNodeCount+=offset;
		if(parent && parent->GetExpanding())
		{
			parent->OnChildTotalVisibleNodesChanged(offset);
		}
	}

	MemoryNodeProvider::MemoryNodeProvider(Ptr<DescriptableObject> _data)
		:data(_data)
	{
		children.ownerProvider=this;
	}

	MemoryNodeProvider::~MemoryNodeProvider()
	{
	}

	Ptr<DescriptableObject> MemoryNodeProvider::GetData()
	{
		return data;
	}

	void MemoryNodeProvider::SetData(const Ptr<DescriptableObject>& value)
	{
		data=value;
		NotifyDataModified();
	}

	MemoryNodeProvider::NodeCollection& MemoryNodeProvider::Children()
	{
		return children;
	}

	bool MemoryNodeProvider::GetExpanding()
	{
		return expanding;
	}

	void MemoryNodeProvider::SetExpanding(bool value)
	{
		if(expanding!=value)
		{
			expanding=value;
			vint offset=0;
			for(vint i=0;i<childCount;i++)
			{
				offset+=children[i]->totalVisibleNodeCount;
			}

			OnChildTotalVisibleNodesChanged(expanding?offset:-offset);
			INodeProviderCallback* proxy=GetCallbackProxyInternal();
			if(proxy)
			{
				if(expanding)
				{
					proxy->OnItemExpanded(this);
				}
				else
				{
					proxy->OnItemCollapsed(this);
				}
			}
		}
	}

	vint MemoryNodeProvider::CalculateTotalVisibleNodes()
	{
		return totalVisibleNodeCount;
	}

	void MemoryNodeProvider::NotifyDataModified()
	{
		if (parent)
		{
			vint index = parent->children.IndexOf(this);
			INodeProviderCallback* proxy = GetCallbackProxyInternal();
			if (proxy)
			{
				proxy->OnBeforeItemModified(parent, index, 1, 1, false);
				proxy->OnAfterItemModified(parent, index, 1, 1, false);
			}
		}
	}

	vint MemoryNodeProvider::GetChildCount()
	{
		return childCount;
	}

	Ptr<INodeProvider> MemoryNodeProvider::GetParent()
	{
		return Ptr(parent);
	}

	Ptr<INodeProvider> MemoryNodeProvider::GetChild(vint index)
	{
		CHECK_ERROR(index >= 0 && index < childCount, L"MemoryNodeProvider::GetChild(vint)#Argument index not in range.");
		return children[index];
	}

/***********************************************************************
NodeRootProviderBase
***********************************************************************/

	void NodeRootProviderBase::OnAttached(INodeRootProvider* provider)
	{
	}

	void NodeRootProviderBase::OnBeforeItemModified(INodeProvider* parentNode, vint start, vint count, vint newCount, bool itemReferenceUpdated)
	{
		// TODO: (enumerable) foreach
		for(vint i=0;i<callbacks.Count();i++)
		{
			callbacks[i]->OnBeforeItemModified(parentNode, start, count, newCount, itemReferenceUpdated);
		}
	}

	void NodeRootProviderBase::OnAfterItemModified(INodeProvider* parentNode, vint start, vint count, vint newCount, bool itemReferenceUpdated)
	{
		// TODO: (enumerable) foreach
		for(vint i=0;i<callbacks.Count();i++)
		{
			callbacks[i]->OnAfterItemModified(parentNode, start, count, newCount, itemReferenceUpdated);
		}
	}

	void NodeRootProviderBase::OnItemExpanded(INodeProvider* node)
	{
		// TODO: (enumerable) foreach
		for(vint i=0;i<callbacks.Count();i++)
		{
			callbacks[i]->OnItemExpanded(node);
		}
	}

	void NodeRootProviderBase::OnItemCollapsed(INodeProvider* node)
	{
		// TODO: (enumerable) foreach
		for(vint i=0;i<callbacks.Count();i++)
		{
			callbacks[i]->OnItemCollapsed(node);
		}
	}

	NodeRootProviderBase::NodeRootProviderBase()
	{
	}

	NodeRootProviderBase::~NodeRootProviderBase()
	{
	}

	bool NodeRootProviderBase::CanGetNodeByVisibleIndex()
	{
		return false;
	}

	Ptr<INodeProvider> NodeRootProviderBase::GetNodeByVisibleIndex(vint index)
	{
		return nullptr;
	}

	bool NodeRootProviderBase::AttachCallback(INodeProviderCallback* value)
	{
		if(callbacks.Contains(value))
		{
			return false;
		}
		else
		{
			callbacks.Add(value);
			value->OnAttached(this);
			return true;
		}
	}

	bool NodeRootProviderBase::DetachCallback(INodeProviderCallback* value)
	{
		vint index=callbacks.IndexOf(value);
		if(index==-1)
		{
			return false;
		}
		else
		{
			value->OnAttached(0);
			callbacks.Remove(value);
			return true;
		}
	}

	IDescriptable* NodeRootProviderBase::RequestView(const WString& identifier)
	{
		return 0;
	}

/***********************************************************************
MemoryNodeRootProvider
***********************************************************************/

	INodeProviderCallback* MemoryNodeRootProvider::GetCallbackProxyInternal()
	{
		return this;
	}

	MemoryNodeRootProvider::MemoryNodeRootProvider()
	{
		SetExpanding(true);
	}

	MemoryNodeRootProvider::~MemoryNodeRootProvider()
	{
	}

	Ptr<INodeProvider> MemoryNodeRootProvider::GetRootNode()
	{
		return Ptr(this);
	}

	MemoryNodeProvider* MemoryNodeRootProvider::GetMemoryNode(INodeProvider* node)
	{
		return dynamic_cast<MemoryNodeProvider*>(node);
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\GUIBINDABLEDATAGRID.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace collections;
			using namespace description;
			using namespace templates;

			namespace list
			{

/***********************************************************************
DataFilterBase
***********************************************************************/

				void DataFilterBase::InvokeOnProcessorChanged()
				{
					if (callback)
					{
						callback->OnProcessorChanged();
					}
				}

				DataFilterBase::DataFilterBase()
				{
				}

				void DataFilterBase::SetCallback(IDataProcessorCallback* value)
				{
					callback = value;
				}

/***********************************************************************
DataMultipleFilter
***********************************************************************/

				DataMultipleFilter::DataMultipleFilter()
				{
				}

				bool DataMultipleFilter::AddSubFilter(Ptr<IDataFilter> value)
				{
					if (!value) return false;
					if (filters.Contains(value.Obj())) return false;
					filters.Add(value);
					value->SetCallback(callback);
					InvokeOnProcessorChanged();
					return true;
				}

				bool DataMultipleFilter::RemoveSubFilter(Ptr<IDataFilter> value)
				{
					if (!value) return false;
					if (!filters.Contains(value.Obj())) return false;
					value->SetCallback(nullptr);
					filters.Remove(value.Obj());
					InvokeOnProcessorChanged();
					return true;
				}

				void DataMultipleFilter::SetCallback(IDataProcessorCallback* value)
				{
					DataFilterBase::SetCallback(value);
					// TODO: (enumerable) foreach
					for (vint i = 0; i < filters.Count(); i++)
					{
						filters[i]->SetCallback(value);
					}
				}

/***********************************************************************
DataAndFilter
***********************************************************************/

				DataAndFilter::DataAndFilter()
				{
				}

				bool DataAndFilter::Filter(const description::Value& row)
				{
					return From(filters)
						.All([row](Ptr<IDataFilter> filter)
					{
						return filter->Filter(row);
					});
				}

/***********************************************************************
DataOrFilter
***********************************************************************/

				DataOrFilter::DataOrFilter()
				{
				}

				bool DataOrFilter::Filter(const description::Value& row)
				{
					return From(filters)
						.Any([row](Ptr<IDataFilter> filter)
					{
						return filter->Filter(row);
					});
				}

/***********************************************************************
DataNotFilter
***********************************************************************/

				DataNotFilter::DataNotFilter()
				{
				}

				bool DataNotFilter::SetSubFilter(Ptr<IDataFilter> value)
				{
					if (filter == value) return false;
					if (filter) filter->SetCallback(nullptr);
					filter = value;
					if (filter) filter->SetCallback(callback);
					InvokeOnProcessorChanged();
					return true;
				}

				void DataNotFilter::SetCallback(IDataProcessorCallback* value)
				{
					DataFilterBase::SetCallback(value);
					if (filter) filter->SetCallback(value);
				}

				bool DataNotFilter::Filter(const description::Value& row)
				{
					return filter ? true : !filter->Filter(row);
				}

/***********************************************************************
DataSorterBase
***********************************************************************/

				void DataSorterBase::InvokeOnProcessorChanged()
				{
					if (callback)
					{
						callback->OnProcessorChanged();
					}
				}

				DataSorterBase::DataSorterBase()
				{
				}

				void DataSorterBase::SetCallback(IDataProcessorCallback* value)
				{
					callback = value;
				}

/***********************************************************************
DataMultipleSorter
***********************************************************************/

				DataMultipleSorter::DataMultipleSorter()
				{
				}

				bool DataMultipleSorter::SetLeftSorter(Ptr<IDataSorter> value)
				{
					if (leftSorter == value) return false;
					if (leftSorter) leftSorter->SetCallback(nullptr);
					leftSorter = value;
					if (leftSorter) leftSorter->SetCallback(callback);
					return true;
				}

				bool DataMultipleSorter::SetRightSorter(Ptr<IDataSorter> value)
				{
					if (rightSorter == value) return false;
					if (rightSorter) rightSorter->SetCallback(nullptr);
					rightSorter = value;
					if (rightSorter) rightSorter->SetCallback(callback);
					return true;
				}

				void DataMultipleSorter::SetCallback(IDataProcessorCallback* value)
				{
					DataSorterBase::SetCallback(value);
					if (leftSorter) leftSorter->SetCallback(value);
					if (rightSorter) rightSorter->SetCallback(value);
				}

				vint DataMultipleSorter::Compare(const description::Value& row1, const description::Value& row2)
				{
					if (leftSorter)
					{
						vint result = leftSorter->Compare(row1, row2);
						if (result != 0) return result;
					}
					if (rightSorter)
					{
						vint result = rightSorter->Compare(row1, row2);
						if (result != 0) return result;
					}
					return 0;
				}

/***********************************************************************
DataReverseSorter
***********************************************************************/

				DataReverseSorter::DataReverseSorter()
				{
				}

				bool DataReverseSorter::SetSubSorter(Ptr<IDataSorter> value)
				{
					if (sorter == value) return false;
					if (sorter) sorter->SetCallback(nullptr);
					sorter = value;
					if (sorter) sorter->SetCallback(callback);
					return true;
				}

				void DataReverseSorter::SetCallback(IDataProcessorCallback* value)
				{
					DataSorterBase::SetCallback(value);
					if (sorter) sorter->SetCallback(value);
				}

				vint DataReverseSorter::Compare(const description::Value& row1, const description::Value& row2)
				{
					return sorter ? -sorter->Compare(row1, row2) : 0;
				}

/***********************************************************************
DataColumn
***********************************************************************/

				void DataColumn::NotifyRebuilt()
				{
					if (dataProvider)
					{
						vint index = dataProvider->columns.IndexOf(this);
						if (index != -1)
						{
							dataProvider->columns.NotifyColumnRebuilt(index);
						}
					}
				}

				void DataColumn::NotifyChanged(bool needToRefreshItems)
				{
					if (dataProvider)
					{
						vint index = dataProvider->columns.IndexOf(this);
						if (index != -1)
						{
							dataProvider->columns.NotifyColumnChanged(index, needToRefreshItems);
						}
					}
				}

				DataColumn::DataColumn()
				{
				}

				DataColumn::~DataColumn()
				{
					if (popup && ownPopup)
					{
						SafeDeleteControl(popup);
					}
				}

				WString DataColumn::GetText()
				{
					return text;
				}

				void DataColumn::SetText(const WString& value)
				{
					if (text != value)
					{
						text = value;
						NotifyChanged(false);
					}
				}

				vint DataColumn::GetSize()
				{
					return size;
				}

				void DataColumn::SetSize(vint value)
				{
					if (size != value)
					{
						size = value;
						NotifyChanged(true);
					}
				}

				bool DataColumn::GetOwnPopup()
				{
					return ownPopup;
				}

				void DataColumn::SetOwnPopup(bool value)
				{
					ownPopup = value;
				}

				GuiMenu* DataColumn::GetPopup()
				{
					return popup;
				}

				void DataColumn::SetPopup(GuiMenu* value)
				{
					if (popup != value)
					{
						popup = value;
						NotifyChanged(false);
					}
				}

				Ptr<IDataFilter> DataColumn::GetFilter()
				{
					return associatedFilter;
				}

				void DataColumn::SetFilter(Ptr<IDataFilter> value)
				{
					if (associatedFilter != value)
					{
						if (associatedFilter) associatedFilter->SetCallback(nullptr);
						associatedFilter = value;
						if (associatedFilter) associatedFilter->SetCallback(dataProvider);

						if (dataProvider)
						{
							vint index = dataProvider->columns.IndexOf(this);
							if (index != -1)
							{
								dataProvider->OnProcessorChanged();
								return;
							}
						}
						NotifyChanged(false);
					}
				}

				Ptr<IDataSorter> DataColumn::GetSorter()
				{
					return associatedSorter;
				}

				void DataColumn::SetSorter(Ptr<IDataSorter> value)
				{
					if (associatedSorter != value)
					{
						if (associatedSorter) associatedSorter->SetCallback(nullptr);
						associatedSorter = value;
						if (associatedSorter) associatedSorter->SetCallback(dataProvider);

						if (dataProvider)
						{
							vint index = dataProvider->columns.IndexOf(this);
							if (index == dataProvider->GetSortedColumn())
							{
								dataProvider->SortByColumn(index, sortingState == ColumnSortingState::Ascending);
								return;
							}
						}
						NotifyChanged(false);
					}
				}

				Ptr<IDataVisualizerFactory> DataColumn::GetVisualizerFactory()
				{
					return visualizerFactory;
				}

				void DataColumn::SetVisualizerFactory(Ptr<IDataVisualizerFactory> value)
				{
					visualizerFactory = value;
					NotifyRebuilt();
				}

				Ptr<IDataEditorFactory> DataColumn::GetEditorFactory()
				{
					return editorFactory;
				}

				void DataColumn::SetEditorFactory(Ptr<IDataEditorFactory> value)
				{
					editorFactory = value;
					NotifyRebuilt();
				}

				WString DataColumn::GetCellText(vint row)
				{
					if (0 <= row && row < dataProvider->Count())
					{
						return ReadProperty(dataProvider->GetBindingValue(row), textProperty);
					}
					return L"";
				}

				description::Value DataColumn::GetCellValue(vint row)
				{
					if (0 <= row && row < dataProvider->Count())
					{
						return ReadProperty(dataProvider->GetBindingValue(row), valueProperty);
					}
					return Value();
				}

				void DataColumn::SetCellValue(vint row, description::Value value)
				{
					if (0 <= row && row < dataProvider->Count())
					{
						auto rowValue = dataProvider->GetBindingValue(row);
						WriteProperty(rowValue, valueProperty, value);
						dataProvider->InvokeOnItemModified(row, 1, 1, false);
					}
				}

				ItemProperty<WString> DataColumn::GetTextProperty()
				{
					return textProperty;
				}

				void DataColumn::SetTextProperty(const ItemProperty<WString>& value)
				{
					if (textProperty != value)
					{
						textProperty = value;
						NotifyRebuilt();
						compositions::GuiEventArgs arguments;
						TextPropertyChanged.Execute(arguments);
					}
				}

				WritableItemProperty<description::Value> DataColumn::GetValueProperty()
				{
					return valueProperty;
				}

				void DataColumn::SetValueProperty(const WritableItemProperty<description::Value>& value)
				{
					if (valueProperty != value)
					{
						valueProperty = value;
						NotifyRebuilt();
						compositions::GuiEventArgs arguments;
						ValuePropertyChanged.Execute(arguments);
					}
				}

/***********************************************************************
DataColumns
***********************************************************************/

				void DataColumns::NotifyColumnRebuilt(vint column)
				{
					NotifyUpdate(column, 1);
				}

				void DataColumns::NotifyColumnChanged(vint column, bool needToRefreshItems)
				{
					dataProvider->NotifyColumnChanged();
				}

				void DataColumns::NotifyUpdateInternal(vint start, vint count, vint newCount)
				{
					dataProvider->NotifyColumnRebuilt();
				}

				bool DataColumns::QueryInsert(vint index, const Ptr<DataColumn>& value)
				{
					return !items.Contains(value.Obj());
				}

				void DataColumns::AfterInsert(vint index, const Ptr<DataColumn>& value)
				{
					value->dataProvider = dataProvider;
				}

				void DataColumns::BeforeRemove(vint index, const Ptr<DataColumn>& value)
				{
					value->dataProvider = nullptr;
				}

				DataColumns::DataColumns(DataProvider* _dataProvider)
					:dataProvider(_dataProvider)
				{
				}

				DataColumns::~DataColumns()
				{
				}

/***********************************************************************
DataProvider
***********************************************************************/

				bool DataProvider::NotifyUpdate(vint start, vint count, bool itemReferenceUpdated)
				{
					if (!itemSource) return false;
					if (start<0 || start >= itemSource->GetCount() || count <= 0 || start + count > itemSource->GetCount())
					{
						return false;
					}
					else
					{
						InvokeOnItemModified(start, count, count, itemReferenceUpdated);
						return true;
					}
				}

				void DataProvider::RebuildAllItems()
				{
					NotifyUpdate(0, Count(), true);
				}

				void DataProvider::RefreshAllItems()
				{
					NotifyUpdate(0, Count(), false);
				}

				void DataProvider::NotifyColumnRebuilt()
				{
					for (auto callback : columnItemViewCallbacks)
					{
						callback->OnColumnRebuilt();
					}
					RefreshAllItems();
				}

				void DataProvider::NotifyColumnChanged()
				{
					for (auto callback : columnItemViewCallbacks)
					{
						callback->OnColumnChanged(true);
					}
					RefreshAllItems();
				}

				list::IItemProvider* DataProvider::GetItemProvider()
				{
					return this;
				}

				void DataProvider::OnProcessorChanged()
				{
					RebuildFilter();
					ReorderRows(true);
				}

				void DataProvider::OnItemSourceModified(vint start, vint count, vint newCount)
				{
					if (!currentSorter && !currentFilter && count == newCount)
					{
						InvokeOnItemModified(start, count, newCount, true);
					}
					else
					{
						ReorderRows(true);
					}
				}

				ListViewDataColumns& DataProvider::GetDataColumns()
				{
					return dataColumns;
				}

				DataColumns& DataProvider::GetColumns()
				{
					return columns;
				}

				Ptr<description::IValueEnumerable> DataProvider::GetItemSource()
				{
					return itemSource;
				}

				void DataProvider::SetItemSource(Ptr<description::IValueEnumerable> _itemSource)
				{
					vint oldCount = 0;
					if (itemSource)
					{
						oldCount = itemSource->GetCount();
					}
					if (itemChangedEventHandler)
					{
						auto ol = itemSource.Cast<IValueObservableList>();
						ol->ItemChanged.Remove(itemChangedEventHandler);
					}

					itemSource = nullptr;
					itemChangedEventHandler = nullptr;

					if (_itemSource)
					{
						if (auto ol = _itemSource.Cast<IValueObservableList>())
						{
							itemSource = ol;
							itemChangedEventHandler = ol->ItemChanged.Add([this](vint start, vint oldCount, vint newCount)
							{
								OnItemSourceModified(start, oldCount, newCount);
							});
						}
						else if (auto rl = _itemSource.Cast<IValueReadonlyList>())
						{
							itemSource = rl;
						}
						else
						{
							itemSource = IValueList::Create(GetLazyList<Value>(_itemSource));
						}
					}

					OnItemSourceModified(0, oldCount, itemSource ? itemSource->GetCount() : 0);
				}

				void DataProvider::RebuildFilter()
				{
					if (currentFilter)
					{
						currentFilter->SetCallback(nullptr);
						currentFilter = nullptr;
					}

					List<Ptr<IDataFilter>> selectedFilters;
					CopyFrom(
						selectedFilters,
						From(columns)
						.Select([](Ptr<DataColumn> column) {return column->GetFilter(); })
						.Where([](Ptr<IDataFilter> filter) {return filter != nullptr; })
					);
					if (additionalFilter)
					{
						selectedFilters.Add(additionalFilter);
					}
					if (selectedFilters.Count() > 0)
					{
						auto andFilter = Ptr(new DataAndFilter);
						for (auto filter : selectedFilters)
						{
							andFilter->AddSubFilter(filter);
						}
						currentFilter = andFilter;
					}

					if (currentFilter)
					{
						currentFilter->SetCallback(this);
					}
				}

				void DataProvider::ReorderRows(bool invokeCallback)
				{
					vint oldRowCount = Count();
					vint rowCount = itemSource ? itemSource->GetCount() : 0;
					virtualRowToSourceRow = nullptr;

					if (currentFilter)
					{
						virtualRowToSourceRow = Ptr(new List<vint>);
						for (vint i = 0; i < rowCount; i++)
						{
							if (currentFilter->Filter(itemSource->Get(i)))
							{
								virtualRowToSourceRow->Add(i);
							}
						}
					}
					else if (currentSorter)
					{
						virtualRowToSourceRow = Ptr(new List<vint>);
						for (vint i = 0; i < rowCount; i++)
						{
							virtualRowToSourceRow->Add(i);
						}
					}

					if (currentSorter && virtualRowToSourceRow->Count() > 0)
					{
						IDataSorter* sorter = currentSorter.Obj();
						SortLambda(
							&virtualRowToSourceRow->operator[](0),
							virtualRowToSourceRow->Count(),
							[=, this](vint a, vint b)
							{
								auto ordering = sorter->Compare(itemSource->Get(a), itemSource->Get(b)) <=> 0;
								return ordering == 0 ? a <=> b : ordering;
							});
					}

					if (invokeCallback)
					{
						vint newRowCount = Count();
						InvokeOnItemModified(0, oldRowCount, newRowCount, true);
					}
				}

				DataProvider::DataProvider()
					:dataColumns(this)
					, columns(this)
				{
					RebuildFilter();
					ReorderRows(false);
				}

				DataProvider::~DataProvider()
				{
					if (itemChangedEventHandler)
					{
						auto ol = itemSource.Cast<IValueObservableList>();
						ol->ItemChanged.Remove(itemChangedEventHandler);
					}
				}

				Ptr<IDataFilter> DataProvider::GetAdditionalFilter()
				{
					return additionalFilter;
				}

				void DataProvider::SetAdditionalFilter(Ptr<IDataFilter> value)
				{
					additionalFilter = value;
					OnProcessorChanged();
				}

				// ===================== GuiListControl::IItemProvider =====================

				vint DataProvider::Count()
				{
					if (itemSource)
					{
						if (virtualRowToSourceRow)
						{
							return virtualRowToSourceRow->Count();
						}
						else
						{
							return itemSource->GetCount();
						}
					}
					else
					{
						return 0;
					}
				}

				WString DataProvider::GetTextValue(vint itemIndex)
				{
					return GetText(itemIndex);
				}

				description::Value DataProvider::GetBindingValue(vint itemIndex)
				{
					if (itemSource)
					{
						if (virtualRowToSourceRow)
						{
							return itemSource->Get(virtualRowToSourceRow->Get(itemIndex));
						}
						else
						{
							return itemSource->Get(itemIndex);
						}
					}
					else
					{
						return Value();
					}
				}

				IDescriptable* DataProvider::RequestView(const WString& identifier)
				{
					if (identifier == IListViewItemView::Identifier)
					{
						return (IListViewItemView*)this;
					}
					else if (identifier == IColumnItemView::Identifier)
					{
						return (IColumnItemView*)this;
					}
					else if (identifier == IDataGridView::Identifier)
					{
						return (IDataGridView*)this;
					}
					else
					{
						return nullptr;
					}
				}

				// ===================== list::IListViewItemProvider =====================

				Ptr<GuiImageData> DataProvider::GetSmallImage(vint itemIndex)
				{
					if (0 <= itemIndex && itemIndex < Count())
					{
						return ReadProperty(GetBindingValue(itemIndex), smallImageProperty);
					}
					return nullptr;
				}

				Ptr<GuiImageData> DataProvider::GetLargeImage(vint itemIndex)
				{
					if (0 <= itemIndex && itemIndex < Count())
					{
						return ReadProperty(GetBindingValue(itemIndex), largeImageProperty);
					}
					return nullptr;
				}

				WString DataProvider::GetText(vint itemIndex)
				{
					if (columns.Count() == 0)return L"";
					return columns[0]->GetCellText(itemIndex);
				}

				WString DataProvider::GetSubItem(vint itemIndex, vint index)
				{
					return columns[index + 1]->GetCellText(itemIndex);
				}

				vint DataProvider::GetDataColumnCount()
				{
					return dataColumns.Count();
				}

				vint DataProvider::GetDataColumn(vint index)
				{
					return dataColumns[index];
				}

				vint DataProvider::GetColumnCount()
				{
					return columns.Count();
				}

				WString DataProvider::GetColumnText(vint index)
				{
					return columns[index]->GetText();
				}

				// ===================== list::ListViewColumnItemArranger::IColumnItemView =====================

				bool DataProvider::AttachCallback(IColumnItemViewCallback* value)
				{
					if (columnItemViewCallbacks.Contains(value))
					{
						return false;
					}
					else
					{
						columnItemViewCallbacks.Add(value);
						return true;
					}
				}

				bool DataProvider::DetachCallback(IColumnItemViewCallback* value)
				{
					vint index = columnItemViewCallbacks.IndexOf(value);
					if (index == -1)
					{
						return false;
					}
					else
					{
						columnItemViewCallbacks.Remove(value);
						return true;
					}
				}

				vint DataProvider::GetColumnSize(vint index)
				{
					return columns[index]->GetSize();
				}

				void DataProvider::SetColumnSize(vint index, vint value)
				{
					columns[index]->SetSize(value);
				}

				GuiMenu* DataProvider::GetDropdownPopup(vint index)
				{
					return columns[index]->GetPopup();
				}

				ColumnSortingState DataProvider::GetSortingState(vint index)
				{
					return columns[index]->sortingState;
				}

				// ===================== list::IDataGridView =====================

				bool DataProvider::IsColumnSortable(vint column)
				{
					return columns[column]->GetSorter();
				}

				void DataProvider::SortByColumn(vint column, bool ascending)
				{
					if (0 <= column && column < columns.Count())
					{
						auto sorter = columns[column]->GetSorter();
						if (!sorter)
						{
							currentSorter = nullptr;
						}
						else if (ascending)
						{
							currentSorter = sorter;
						}
						else
						{
							auto reverseSorter = Ptr(new DataReverseSorter);
							reverseSorter->SetSubSorter(sorter);
							currentSorter = reverseSorter;
						}
					}
					else
					{
						currentSorter = nullptr;
					}

					// TODO: (enumerable) foreach:indexed
					for (vint i = 0; i < columns.Count(); i++)
					{
						columns[i]->sortingState =
							i != column ? ColumnSortingState::NotSorted :
							ascending ? ColumnSortingState::Ascending :
							ColumnSortingState::Descending
							;
					}
					NotifyColumnChanged();
					ReorderRows(true);
				}

				vint DataProvider::GetSortedColumn()
				{
					// TODO: (enumerable) foreach:indexed
					for (vint i = 0; i < columns.Count(); i++)
					{
						auto state = columns[i]->sortingState;
						if (state != ColumnSortingState::NotSorted)
						{
							return i;
						}
					}
					return -1;
				}

				bool DataProvider::IsSortOrderAscending()
				{
					// TODO: (enumerable) foreach
					for (vint i = 0; i < columns.Count(); i++)
					{
						auto state = columns[i]->sortingState;
						if (state != ColumnSortingState::NotSorted)
						{
							return state == ColumnSortingState::Ascending;
						}
					}
					return true;
				}

				vint DataProvider::GetCellSpan(vint row, vint column)
				{
					return 1;
				}

				IDataVisualizerFactory* DataProvider::GetCellDataVisualizerFactory(vint row, vint column)
				{
					return columns[column]->GetVisualizerFactory().Obj();
				}

				IDataEditorFactory* DataProvider::GetCellDataEditorFactory(vint row, vint column)
				{
					return columns[column]->GetEditorFactory().Obj();
				}

				description::Value DataProvider::GetBindingCellValue(vint row, vint column)
				{
					return columns[column]->GetCellValue(row);
				}

				void DataProvider::SetBindingCellValue(vint row, vint column, const description::Value& value)
				{
					columns[column]->SetCellValue(row, value);
				}
			}

/***********************************************************************
GuiBindableDataGrid
***********************************************************************/

			GuiBindableDataGrid::GuiBindableDataGrid(theme::ThemeName themeName)
				:GuiVirtualDataGrid(themeName, new list::DataProvider)
			{
				dataProvider = dynamic_cast<list::DataProvider*>(GetItemProvider());
			}

			GuiBindableDataGrid::~GuiBindableDataGrid()
			{
			}
			
			list::ListViewDataColumns& GuiBindableDataGrid::GetDataColumns()
			{
				return dataProvider->GetDataColumns();
			}

			list::DataColumns& GuiBindableDataGrid::GetColumns()
			{
				return dataProvider->GetColumns();
			}

			Ptr<description::IValueEnumerable> GuiBindableDataGrid::GetItemSource()
			{
				return dataProvider->GetItemSource();
			}

			void GuiBindableDataGrid::SetItemSource(Ptr<description::IValueEnumerable> _itemSource)
			{
				dataProvider->SetItemSource(_itemSource);
			}

			Ptr<list::IDataFilter> GuiBindableDataGrid::GetAdditionalFilter()
			{
				return dataProvider->GetAdditionalFilter();
			}

			void GuiBindableDataGrid::SetAdditionalFilter(Ptr<list::IDataFilter> value)
			{
				dataProvider->SetAdditionalFilter(value);
			}

			ItemProperty<Ptr<GuiImageData>> GuiBindableDataGrid::GetLargeImageProperty()
			{
				return dataProvider->largeImageProperty;
			}

			void GuiBindableDataGrid::SetLargeImageProperty(const ItemProperty<Ptr<GuiImageData>>& value)
			{
				if (dataProvider->largeImageProperty != value)
				{
					dataProvider->largeImageProperty = value;
					dataProvider->RefreshAllItems();
					LargeImagePropertyChanged.Execute(GetNotifyEventArguments());
				}
			}

			ItemProperty<Ptr<GuiImageData>> GuiBindableDataGrid::GetSmallImageProperty()
			{
				return dataProvider->smallImageProperty;
			}

			void GuiBindableDataGrid::SetSmallImageProperty(const ItemProperty<Ptr<GuiImageData>>& value)
			{
				if (dataProvider->smallImageProperty != value)
				{
					dataProvider->smallImageProperty = value;
					dataProvider->RefreshAllItems();
					SmallImagePropertyChanged.Execute(GetNotifyEventArguments());
				}
			}

			description::Value GuiBindableDataGrid::GetSelectedRowValue()
			{
				auto pos = GetSelectedCell();
				if (pos.row == -1 || pos.column == -1)
				{
					return Value();
				}
				return dataProvider->GetBindingValue(GetSelectedCell().row);
			}

			description::Value GuiBindableDataGrid::GetSelectedCellValue()
			{
				auto pos = GetSelectedCell();
				if (pos.row == -1 || pos.column == -1)
				{
					return Value();
				}
				return dataProvider->GetColumns()[pos.column]->GetCellValue(pos.row);
			}

			bool GuiBindableDataGrid::NotifyItemDataModified(vint start, vint count)
			{
				StopEdit();
				return dataProvider->NotifyUpdate(start, count, false);
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\GUIBINDABLELISTCONTROLS.CPP
***********************************************************************/

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

/***********************************************************************
GuiBindableTextList
***********************************************************************/

			GuiBindableTextList::GuiBindableTextList(theme::ThemeName themeName)
				:GuiVirtualTextList(themeName, new TextItemBindableProvider)
			{
				itemSource = dynamic_cast<TextItemBindableProvider*>(GetItemProvider());

				TextPropertyChanged.SetAssociatedComposition(boundsComposition);
				TextPropertyChanged.SetAssociatedComposition(boundsComposition);
			}

			GuiBindableTextList::~GuiBindableTextList()
			{
			}

			Ptr<description::IValueEnumerable> GuiBindableTextList::GetItemSource()
			{
				return itemSource->GetItemSource();
			}

			void GuiBindableTextList::SetItemSource(Ptr<description::IValueEnumerable> _itemSource)
			{
				itemSource->SetItemSource(_itemSource);
			}

			ItemProperty<WString> GuiBindableTextList::GetTextProperty()
			{
				return itemSource->textProperty;
			}

			void GuiBindableTextList::SetTextProperty(const ItemProperty<WString>& value)
			{
				if (itemSource->textProperty != value)
				{
					itemSource->textProperty = value;
					itemSource->UpdateBindingProperties();
					TextPropertyChanged.Execute(GetNotifyEventArguments());
				}
			}

			WritableItemProperty<bool> GuiBindableTextList::GetCheckedProperty()
			{
				return itemSource->checkedProperty;
			}

			void GuiBindableTextList::SetCheckedProperty(const WritableItemProperty<bool>& value)
			{
				if (itemSource->checkedProperty != value)
				{
					itemSource->checkedProperty = value;
					itemSource->UpdateBindingProperties();
					CheckedPropertyChanged.Execute(GetNotifyEventArguments());
				}
			}

			description::Value GuiBindableTextList::GetSelectedItem()
			{
				vint index = GetSelectedItemIndex();
				if (index == -1) return Value();
				return itemSource->Get(index);
			}

			bool GuiBindableTextList::NotifyItemDataModified(vint start, vint count)
			{
				return itemSource->NotifyUpdate(start, count, false);
			}

/***********************************************************************
GuiBindableListView
***********************************************************************/

			GuiBindableListView::GuiBindableListView(theme::ThemeName themeName)
				:GuiVirtualListView(themeName, new ListViewItemBindableProvider)
			{
				itemSource = dynamic_cast<ListViewItemBindableProvider*>(GetItemProvider());

				LargeImagePropertyChanged.SetAssociatedComposition(boundsComposition);
				SmallImagePropertyChanged.SetAssociatedComposition(boundsComposition);
			}

			GuiBindableListView::~GuiBindableListView()
			{
			}

			list::ListViewDataColumns& GuiBindableListView::GetDataColumns()
			{
				return itemSource->GetDataColumns();
			}

			list::ListViewColumns& GuiBindableListView::GetColumns()
			{
				return itemSource->GetColumns();
			}

			Ptr<description::IValueEnumerable> GuiBindableListView::GetItemSource()
			{
				return itemSource->GetItemSource();
			}

			void GuiBindableListView::SetItemSource(Ptr<description::IValueEnumerable> _itemSource)
			{
				itemSource->SetItemSource(_itemSource);
			}

			ItemProperty<Ptr<GuiImageData>> GuiBindableListView::GetLargeImageProperty()
			{
				return itemSource->largeImageProperty;
			}

			void GuiBindableListView::SetLargeImageProperty(const ItemProperty<Ptr<GuiImageData>>& value)
			{
				if (itemSource->largeImageProperty != value)
				{
					itemSource->largeImageProperty = value;
					itemSource->UpdateBindingProperties();
					LargeImagePropertyChanged.Execute(GetNotifyEventArguments());
				}
			}

			ItemProperty<Ptr<GuiImageData>> GuiBindableListView::GetSmallImageProperty()
			{
				return itemSource->smallImageProperty;
			}

			void GuiBindableListView::SetSmallImageProperty(const ItemProperty<Ptr<GuiImageData>>& value)
			{
				if (itemSource->smallImageProperty != value)
				{
					itemSource->smallImageProperty = value;
					itemSource->UpdateBindingProperties();
					SmallImagePropertyChanged.Execute(GetNotifyEventArguments());
				}
			}

			description::Value GuiBindableListView::GetSelectedItem()
			{
				vint index = GetSelectedItemIndex();
				if (index == -1) return Value();
				return itemSource->Get(index);
			}

			bool GuiBindableListView::NotifyItemDataModified(vint start, vint count)
			{
				return itemSource->NotifyUpdate(start, count, false);
			}

/***********************************************************************
GuiBindableTreeView
***********************************************************************/

			GuiBindableTreeView::GuiBindableTreeView(theme::ThemeName themeName, WritableItemProperty<description::Value> reverseMappingProperty)
				:GuiVirtualTreeView(themeName, Ptr(new TreeViewItemBindableRootProvider))
			{
				itemSource = dynamic_cast<TreeViewItemBindableRootProvider*>(GetNodeRootProvider());
				itemSource->reverseMappingProperty = reverseMappingProperty;

				TextPropertyChanged.SetAssociatedComposition(boundsComposition);
				ImagePropertyChanged.SetAssociatedComposition(boundsComposition);
				ChildrenPropertyChanged.SetAssociatedComposition(boundsComposition);
			}

			GuiBindableTreeView::~GuiBindableTreeView()
			{
			}

			description::Value GuiBindableTreeView::GetItemSource()
			{
				return itemSource->GetItemSource();
			}

			void GuiBindableTreeView::SetItemSource(description::Value _itemSource)
			{
				itemSource->SetItemSource(_itemSource);
			}
			
			WritableItemProperty<description::Value> GuiBindableTreeView::GetReverseMappingProperty()
			{
				return itemSource->reverseMappingProperty;
			}

			ItemProperty<WString> GuiBindableTreeView::GetTextProperty()
			{
				return itemSource->textProperty;
			}

			void GuiBindableTreeView::SetTextProperty(const ItemProperty<WString>& value)
			{
				if (itemSource->textProperty != value)
				{
					itemSource->textProperty = value;
					itemSource->UpdateBindingProperties(false);
					TextPropertyChanged.Execute(GetNotifyEventArguments());
				}
			}

			ItemProperty<Ptr<GuiImageData>> GuiBindableTreeView::GetImageProperty()
			{
				return itemSource->imageProperty;
			}

			void GuiBindableTreeView::SetImageProperty(const ItemProperty<Ptr<GuiImageData>>& value)
			{
				if (itemSource->imageProperty != value)
				{
					itemSource->imageProperty = value;
					itemSource->UpdateBindingProperties(false);
					ImagePropertyChanged.Execute(GetNotifyEventArguments());
				}
			}

			ItemProperty<Ptr<IValueEnumerable>> GuiBindableTreeView::GetChildrenProperty()
			{
				return itemSource->childrenProperty;
			}

			void GuiBindableTreeView::SetChildrenProperty(const ItemProperty<Ptr<IValueEnumerable>>& value)
			{
				if (itemSource->childrenProperty != value)
				{
					itemSource->childrenProperty = value;
					itemSource->UpdateBindingProperties(true);
					ChildrenPropertyChanged.Execute(GetNotifyEventArguments());
				}
			}

			description::Value GuiBindableTreeView::GetSelectedItem()
			{
				vint index = GetSelectedItemIndex();
				if (index == -1) return Value();

				Value result;
				if (auto node = nodeItemView->RequestNode(index))
				{
					if (auto itemSourceNode = node.Cast<TreeViewItemBindableNode>())
					{
						result = itemSourceNode->GetItemSource();
					}
				}
				return result;
			}

			void GuiBindableTreeView::NotifyNodeDataModified(description::Value value)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::GuiBindableTreeView::NotifyNodeDataModified(Value)#"

				CHECK_ERROR(itemSource->reverseMappingProperty, ERROR_MESSAGE_PREFIX L"This function can only be called when the ReverseMappingProperty is in use.");
				CHECK_ERROR(!value.IsNull(), ERROR_MESSAGE_PREFIX L"The item cannot be null.");
				auto mapping = ReadProperty(value, itemSource->reverseMappingProperty);
				auto node = dynamic_cast<tree::INodeProvider*>(mapping.GetRawPtr());
				CHECK_ERROR(node, ERROR_MESSAGE_PREFIX L"The item is not binded to a GuiBindableTreeView control or its reverse mapping property has been unexpectedly changed.");

				auto rootNode = node;
				while (rootNode->GetParent())
				{
					rootNode = rootNode->GetParent().Obj();
				}

				CHECK_ERROR(rootNode == itemSource->rootNode.Obj(), ERROR_MESSAGE_PREFIX L"The item is not binded to this control.");
				CHECK_ERROR(node != itemSource->rootNode.Obj(), ERROR_MESSAGE_PREFIX L"The item should not be the root item, which is the item source assigned to this control.");
				node->NotifyDataModified();

#undef ERROR_MESSAGE_PREFIX
			}
		}
	}
}


/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\GUICOMBOCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{

/***********************************************************************
GuiComboBoxBase
***********************************************************************/

			void GuiComboBoxBase::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiComboBoxBase::AfterControlTemplateInstalled_(bool initialize)
			{
			}

			compositions::IGuiAltActionHost* GuiComboBoxBase::GetActivatingAltHost()
			{
				// When the combo box is opened by an Alt action, it will hot continue into the dropdown
				return GuiSelectableButton::GetActivatingAltHost();
			}

			IGuiMenuService::Direction GuiComboBoxBase::GetSubMenuDirection()
			{
				return IGuiMenuService::Horizontal;
			}

			void GuiComboBoxBase::OnCachedBoundsChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				Size size=GetPreferredMenuClientSize();
				size.x=boundsComposition->GetCachedBounds().Width();
				SetPreferredMenuClientSize(size);
			}

			void GuiComboBoxBase::OnKeyDown(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
				if (arguments.code == VKEY::KEY_SPACE && !arguments.ctrl && !arguments.shift && !arguments.alt)
				{
					GetSubMenu()->Hide();
					arguments.handled = true;
				}
			}

			void GuiComboBoxBase::OnAfterSubMenuOpening(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (autoFocusDropdown && GetSubMenu())
				{
					GetSubMenu()->SetFocused();
				}
			}

			GuiComboBoxBase::GuiComboBoxBase(theme::ThemeName themeName, bool _autoFocusDropdown)
				:GuiMenuButton(themeName)
				, autoFocusDropdown(_autoFocusDropdown)
			{
				CreateSubMenu();
				SetCascadeAction(false);

				boundsComposition->CachedBoundsChanged.AttachMethod(this, &GuiComboBoxBase::OnCachedBoundsChanged);
				boundsComposition->GetEventReceiver()->keyDown.AttachMethod(this, &GuiComboBoxBase::OnKeyDown);
				
				if (autoFocusDropdown)
				{
					AfterSubMenuOpening.AttachMethod(this, &GuiComboBoxBase::OnAfterSubMenuOpening);
				}
			}

			GuiComboBoxBase::~GuiComboBoxBase()
			{
			} 

			IDescriptable* GuiComboBoxBase::QueryService(const WString& identifier)
			{
				if (identifier == IGuiMenuService::Identifier)
				{
					// Stop cascading menu behavior if the combo box is put in another combo box dropdown
					return nullptr;
				}
				else
				{
					return GuiMenuButton::QueryService(identifier);
				}
			}

/***********************************************************************
GuiComboButton
***********************************************************************/

			GuiComboButton::GuiComboButton(theme::ThemeName themeName, GuiControl* _dropdownControl)
				:GuiComboBoxBase(themeName, false)
				, dropdownControl(_dropdownControl)
			{
				dropdownControl->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
				GetSubMenu()->GetContainerComposition()->AddChild(dropdownControl->GetBoundsComposition());
			}

			GuiComboButton::~GuiComboButton()
			{
			}

/***********************************************************************
GuiComboBoxListControl
***********************************************************************/

			void GuiComboBoxListControl::UpdateDisplayFont()
			{
				GuiControl::UpdateDisplayFont();
				if (itemStyleController)
				{
					itemStyleController->SetFont(GetDisplayFont());
				}
			}

			void GuiComboBoxListControl::BeforeControlTemplateUninstalled()
			{
				GuiComboBoxBase::BeforeControlTemplateUninstalled();
			}

			void GuiComboBoxListControl::AfterControlTemplateInstalled(bool initialize)
			{
				GuiComboBoxBase::AfterControlTemplateInstalled(initialize);
				TypedControlTemplateObject(true)->SetTextVisible(!itemStyleProperty);
			}

			void GuiComboBoxListControl::RemoveStyleController()
			{
				if (itemStyleController)
				{
					SafeDeleteComposition(itemStyleController);
					itemStyleController = nullptr;
				}
			}

			void GuiComboBoxListControl::InstallStyleController(vint itemIndex)
			{
				if (itemStyleProperty)
				{
					if (itemIndex != -1)
					{
						auto item = containedListControl->GetItemProvider()->GetBindingValue(itemIndex);
						if (!item.IsNull())
						{
							if (auto style = itemStyleProperty(item))
							{
								itemStyleController = style;
								itemStyleController->SetText(GetText());
								itemStyleController->SetFont(GetDisplayFont());
								itemStyleController->SetContext(GetContext());
								itemStyleController->SetVisuallyEnabled(GetVisuallyEnabled());
								itemStyleController->SetAlignmentToParent(Margin(0, 0, 0, 0));
								containerComposition->AddChild(itemStyleController);
							}
						}
					}
				}
			}

			void GuiComboBoxListControl::DisplaySelectedContent(vint itemIndex)
			{
				if (itemIndex == -1)
				{
					SetText(L"");
				}
				else
				{
					WString text = containedListControl->GetItemProvider()->GetTextValue(itemIndex);
					SetText(text);
				}

				RemoveStyleController();
				InstallStyleController(itemIndex);
				if (selectedIndex != itemIndex)
				{
					selectedIndex = itemIndex;
					SelectedIndexChanged.Execute(GetNotifyEventArguments());
				}
			}

			void GuiComboBoxListControl::AdoptSubMenuSize()
			{
				if (auto subMenu = GetSubMenu())
				{
					Size expectedSize(0, GetDisplayFont().size * 20);
					Size adoptedSize = containedListControl->GetAdoptedSize(expectedSize);

					Size clientSize = GetPreferredMenuClientSize();
					vint height = adoptedSize.y + subMenu->GetClientSize().y - containedListControl->GetBoundsComposition()->GetCachedBounds().Height();
					if (clientSize.y != height)
					{
						clientSize.y = height;
						SetPreferredMenuClientSize(clientSize);
					}
				}
			}

			void GuiComboBoxListControl::OnTextChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (itemStyleController)
				{
					itemStyleController->SetText(GetText());
				}
			}

			void GuiComboBoxListControl::OnContextChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (itemStyleController)
				{
					itemStyleController->SetContext(GetContext());
				}
			}

			void GuiComboBoxListControl::OnVisuallyEnabledChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (itemStyleController)
				{
					itemStyleController->SetVisuallyEnabled(GetVisuallyEnabled());
				}
			}

			void GuiComboBoxListControl::OnAfterSubMenuOpening(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				containedListControl->SelectItemsByClick(selectedIndex, false, false, true);
				containedListControl->EnsureItemVisible(selectedIndex);
			}

			void GuiComboBoxListControl::OnListControlAdoptedSizeInvalidated(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				TryDelayExecuteIfNotDeleted([=, this]() { AdoptSubMenuSize(); });
			}

			void GuiComboBoxListControl::OnListControlItemMouseDown(compositions::GuiGraphicsComposition* sender, compositions::GuiItemMouseEventArgs& arguments)
			{
				DisplaySelectedContent(containedListControl->GetSelectedItemIndex());
				GetSubMenu()->Hide();
			}

			void GuiComboBoxListControl::OnKeyDown(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
				if (!arguments.autoRepeatKeyDown)
				{
					switch (arguments.code)
					{
					case VKEY::KEY_RETURN:
						DisplaySelectedContent(containedListControl->GetSelectedItemIndex());
						GetSubMenu()->Hide();
						arguments.handled = true;
						break;
					default:
						containedListControl->SelectItemsByKey(arguments.code, arguments.ctrl, arguments.shift);
					}
				}
			}

			void GuiComboBoxListControl::OnAttached(list::IItemProvider* provider)
			{
			}

			void GuiComboBoxListControl::OnItemModified(vint start, vint count, vint newCount, bool itemReferenceUpdated)
			{
				if (count == newCount && start <= selectedIndex && selectedIndex < start + count)
				{
					DisplaySelectedContent(selectedIndex);
				}
				else
				{
					DisplaySelectedContent(-1);
				}
			}

			GuiComboBoxListControl::GuiComboBoxListControl(theme::ThemeName themeName, GuiSelectableListControl* _containedListControl)
				:GuiComboBoxBase(themeName, false)
				, containedListControl(_containedListControl)
			{
				TextChanged.AttachMethod(this, &GuiComboBoxListControl::OnTextChanged);
				ContextChanged.AttachMethod(this, &GuiComboBoxListControl::OnContextChanged);
				VisuallyEnabledChanged.AttachMethod(this, &GuiComboBoxListControl::OnVisuallyEnabledChanged);
				AfterSubMenuOpening.AttachMethod(this, &GuiComboBoxListControl::OnAfterSubMenuOpening);

				containedListControl->GetItemProvider()->AttachCallback(this);
				containedListControl->SetMultiSelect(false);
				containedListControl->AdoptedSizeInvalidated.AttachMethod(this, &GuiComboBoxListControl::OnListControlAdoptedSizeInvalidated);
				containedListControl->ItemLeftButtonDown.AttachMethod(this, &GuiComboBoxListControl::OnListControlItemMouseDown);
				containedListControl->ItemRightButtonDown.AttachMethod(this, &GuiComboBoxListControl::OnListControlItemMouseDown);
				boundsComposition->GetEventReceiver()->keyDown.AttachMethod(this, &GuiComboBoxListControl::OnKeyDown);

				auto itemProvider = containedListControl->GetItemProvider();

				SelectedIndexChanged.SetAssociatedComposition(boundsComposition);

				containedListControl->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
				GetSubMenu()->GetContainerComposition()->AddChild(containedListControl->GetBoundsComposition());
				SetFont(GetFont());
			}

			GuiComboBoxListControl::~GuiComboBoxListControl()
			{
				containedListControl->GetItemProvider()->DetachCallback(this);
				containedListControl->GetBoundsComposition()->CachedBoundsChanged.Detach(boundsChangedHandler);
				boundsChangedHandler = nullptr;
			}

			GuiSelectableListControl* GuiComboBoxListControl::GetContainedListControl()
			{
				return containedListControl;
			}

			GuiComboBoxListControl::ItemStyleProperty GuiComboBoxListControl::GetItemTemplate()
			{
				return itemStyleProperty;
			}

			void GuiComboBoxListControl::SetItemTemplate(ItemStyleProperty value)
			{
				RemoveStyleController();
				itemStyleProperty = value;
				TypedControlTemplateObject(true)->SetTextVisible(!itemStyleProperty);
				InstallStyleController(selectedIndex);
				ItemTemplateChanged.Execute(GetNotifyEventArguments());
			}

			vint GuiComboBoxListControl::GetSelectedIndex()
			{
				return selectedIndex;
			}

			void GuiComboBoxListControl::SetSelectedIndex(vint value)
			{
				if (selectedIndex != value)
				{
					if (0 <= value && value < containedListControl->GetItemProvider()->Count())
					{
						DisplaySelectedContent(value);
					}
				}
				GetSubMenu()->Hide();
			}

			description::Value GuiComboBoxListControl::GetSelectedItem()
			{
				if (selectedIndex != -1)
				{
					return containedListControl->GetItemProvider()->GetBindingValue(selectedIndex);
				}
				return description::Value();
			}

			list::IItemProvider* GuiComboBoxListControl::GetItemProvider()
			{
				return containedListControl->GetItemProvider();
			}
		}
	}
}


/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\GUIDATAGRIDCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			namespace list
			{
				using namespace compositions;
				using namespace collections;
				using namespace description;
				using namespace templates;

				const wchar_t* const IDataGridView::Identifier = L"vl::presentation::controls::list::IDataGridView";

/***********************************************************************
DefaultDataGridItemTemplate
***********************************************************************/

				IDataVisualizerFactory* DefaultDataGridItemTemplate::GetDataVisualizerFactory(vint row, vint column)
				{
					if (auto dataGrid = dynamic_cast<GuiVirtualDataGrid*>(listControl))
					{
						if (auto factory = dataGrid->dataGridView->GetCellDataVisualizerFactory(row, column))
						{
							return factory;
						}

						if (column == 0)
						{
							return dataGrid->defaultMainColumnVisualizerFactory.Obj();
						}
						else
						{
							return dataGrid->defaultSubColumnVisualizerFactory.Obj();
						}

					}

					return nullptr;
				}

				IDataEditorFactory* DefaultDataGridItemTemplate::GetDataEditorFactory(vint row, vint column)
				{
					if (auto dataGrid = dynamic_cast<GuiVirtualDataGrid*>(listControl))
					{
						return dataGrid->dataGridView->GetCellDataEditorFactory(row, column);
					}
					return nullptr;
				}

				vint DefaultDataGridItemTemplate::GetCellColumnIndex(compositions::GuiGraphicsComposition* composition)
				{
					for (vint i = 0; i < textTable->GetColumns(); i++)
					{
						auto cell = textTable->GetSitedCell(0, i);
						if (composition == cell)
						{
							return i;
						}
					}
					return -1;
				}

				bool DefaultDataGridItemTemplate::IsInEditor(GuiVirtualDataGrid* dataGrid, compositions::GuiMouseEventArgs& arguments)
				{
					if (!dataGrid->currentEditor) return false;
					auto editorComposition = dataGrid->currentEditor->GetTemplate();
					auto currentComposition = arguments.eventSource;

					while (currentComposition)
					{
						if (currentComposition == editorComposition)
						{
							return true;
						}
						else if (currentComposition == this)
						{
							break;
						}
						else
						{
							currentComposition = currentComposition->GetParent();
						}
					}

					return false;
				}

				void DefaultDataGridItemTemplate::OnCellButtonDown(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
				{
					if (auto dataGrid = dynamic_cast<GuiVirtualDataGrid*>(listControl))
					{
						if (IsInEditor(dataGrid, arguments))
						{
							arguments.handled = true;
						}
					}
				}

				void DefaultDataGridItemTemplate::OnCellLeftButtonUp(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
				{
					if (auto dataGrid = dynamic_cast<GuiVirtualDataGrid*>(listControl))
					{
						if (IsInEditor(dataGrid, arguments))
						{
							arguments.handled = true;
						}
						else if (dataGrid->GetVisuallyEnabled())
						{
							vint index = GetCellColumnIndex(sender);
							if (index != -1)
							{
								vint currentRow = GetIndex();
								dataGrid->SelectCell({ currentRow,index }, true);
							}
						}
					}
				}

				void DefaultDataGridItemTemplate::OnCellRightButtonUp(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
				{
					if (auto dataGrid = dynamic_cast<GuiVirtualDataGrid*>(listControl))
					{
						if (IsInEditor(dataGrid, arguments))
						{
							arguments.handled = true;
						}
						else if (dataGrid->GetVisuallyEnabled())
						{
							vint index = GetCellColumnIndex(sender);
							if (index != -1)
							{
								vint currentRow = GetIndex();
								dataGrid->SelectCell({ currentRow,index }, false);
							}
						}
					}
				}

				void DefaultDataGridItemTemplate::DeleteAllVisualizers()
				{
					for (vint i = 0; i < dataVisualizers.Count(); i++)
					{
						DeleteVisualizer(i);
					}
				}

				void DefaultDataGridItemTemplate::DeleteVisualizer(vint column)
				{
					auto visualizer = dataVisualizers[column];
					auto composition = visualizer->GetTemplate();
					visualizer->NotifyDeletedTemplate();
					if (composition->GetParent())
					{
						composition->GetParent()->RemoveChild(composition);
					}
					SafeDeleteComposition(composition);
					dataVisualizers[column] = nullptr;
				}

				void DefaultDataGridItemTemplate::ResetDataTable(vint columnCount)
				{
					vint itemIndex = GetIndex();

					if (dataVisualizers.Count() == columnCount)
					{
						for (vint i = 0; i < columnCount; i++)
						{
							auto factory = GetDataVisualizerFactory(itemIndex, i);
							if (dataVisualizerFactories[i] != factory)
							{
								DeleteVisualizer(i);
								dataVisualizerFactories[i] = factory;
							}
						}
					}
					else
					{
						DeleteAllVisualizers();
						dataVisualizerFactories.Resize(columnCount);
						dataVisualizers.Resize(columnCount);

						for (auto cell : dataCells)
						{
							SafeDeleteComposition(cell);
						}
						dataCells.Resize(columnCount);
						
						for (vint i = 0; i < columnCount; i++)
						{
							dataVisualizerFactories[i] = GetDataVisualizerFactory(itemIndex, i);
						}

						textTable->SetRowsAndColumns(1, columnCount);
						for (vint i = 0; i < columnCount; i++)
						{
							auto cell = new GuiCellComposition;
							textTable->AddChild(cell);
							cell->SetSite(0, i, 1, 1);
							cell->GetEventReceiver()->leftButtonDown.AttachMethod(this, &DefaultDataGridItemTemplate::OnCellButtonDown);
							cell->GetEventReceiver()->rightButtonDown.AttachMethod(this, &DefaultDataGridItemTemplate::OnCellButtonDown);
							cell->GetEventReceiver()->leftButtonUp.AttachMethod(this, &DefaultDataGridItemTemplate::OnCellLeftButtonUp);
							cell->GetEventReceiver()->rightButtonUp.AttachMethod(this, &DefaultDataGridItemTemplate::OnCellRightButtonUp);
							dataCells[i] = cell;
						}
					}
				}

				void DefaultDataGridItemTemplate::OnInitialize()
				{
					{
						textTable = new GuiTableComposition;
						textTable->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
						textTable->SetAlignmentToParent(Margin(0, 0, 0, 0));
						textTable->SetRowsAndColumns(1, 1);
						textTable->SetRowOption(0, GuiCellOption::MinSizeOption());
						textTable->SetColumnOption(0, GuiCellOption::AbsoluteOption(0));
						AddChild(textTable);
					}

					SelectedChanged.AttachMethod(this, &DefaultDataGridItemTemplate::OnSelectedChanged);
					FontChanged.AttachMethod(this, &DefaultDataGridItemTemplate::OnFontChanged);
					ContextChanged.AttachMethod(this, &DefaultDataGridItemTemplate::OnContextChanged);
					VisuallyEnabledChanged.AttachMethod(this, &DefaultDataGridItemTemplate::OnVisuallyEnabledChanged);

					SelectedChanged.Execute(compositions::GuiEventArgs(this));
					FontChanged.Execute(compositions::GuiEventArgs(this));
					ContextChanged.Execute(compositions::GuiEventArgs(this));
					VisuallyEnabledChanged.Execute(compositions::GuiEventArgs(this));
				}

				void DefaultDataGridItemTemplate::OnRefresh()
				{
					if (auto dataGrid = dynamic_cast<GuiVirtualDataGrid*>(listControl))
					{
						vint columnCount = dataGrid->listViewItemView->GetColumnCount();
						vint itemIndex = GetIndex();
						ResetDataTable(columnCount);

						for (vint i = 0; i < columnCount; i++)
						{
							auto& dataVisualizer = dataVisualizers[i];
							if (!dataVisualizer)
							{
								dataVisualizer = dataVisualizerFactories[i]->CreateVisualizer(dataGrid);
								dataVisualizer->GetTemplate()->SetFont(GetFont());
								dataVisualizers[i] = dataVisualizer;

								auto cell = dataCells[i];
								auto composition = dataVisualizer->GetTemplate();
								composition->SetAlignmentToParent(Margin(0, 0, 0, 0));
								cell->AddChild(composition);
							}
							dataVisualizer->BeforeVisualizeCell(dataGrid->GetItemProvider(), itemIndex, i);
						}

						GridPos selectedCell = dataGrid->GetSelectedCell();
						if (selectedCell.row == itemIndex)
						{
							NotifySelectCell(selectedCell.column);
						}
						else
						{
							NotifySelectCell(-1);
						}
					}
					UpdateSubItemSize();
				}

				void DefaultDataGridItemTemplate::OnSelectedChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					if (!GetSelected())
					{
						NotifySelectCell(-1);
					}
				}

				void DefaultDataGridItemTemplate::OnFontChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					for (auto visualizer : dataVisualizers)
					{
						visualizer->GetTemplate()->SetFont(GetFont());
					}
					if (currentEditor)
					{
						currentEditor->GetTemplate()->SetFont(GetFont());
					}
				}

				void DefaultDataGridItemTemplate::OnContextChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					for (auto visualizer : dataVisualizers)
					{
						visualizer->GetTemplate()->SetContext(GetContext());
					}
					if (currentEditor)
					{
						currentEditor->GetTemplate()->SetContext(GetContext());
					}
				}

				void DefaultDataGridItemTemplate::OnVisuallyEnabledChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					for (auto visualizer : dataVisualizers)
					{
						visualizer->GetTemplate()->SetVisuallyEnabled(GetVisuallyEnabled());
					}
					if (currentEditor)
					{
						currentEditor->GetTemplate()->SetVisuallyEnabled(GetVisuallyEnabled());
					}
				}

				DefaultDataGridItemTemplate::DefaultDataGridItemTemplate()
				{
				}

				DefaultDataGridItemTemplate::~DefaultDataGridItemTemplate()
				{
					for (auto visualizer : dataVisualizers)
					{
						visualizer->NotifyDeletedTemplate();
					}
					if (currentEditor)
					{
						currentEditor->NotifyDeletedTemplate();
					}
				}

				void DefaultDataGridItemTemplate::UpdateSubItemSize()
				{
					if (auto dataGrid = dynamic_cast<GuiVirtualDataGrid*>(listControl))
					{
						vint columnCount = dataGrid->listViewItemView->GetColumnCount();
						if (columnCount > textTable->GetColumns())
						{
							columnCount = textTable->GetColumns();
						}
						for (vint i = 0; i < columnCount; i++)
						{
							textTable->SetColumnOption(i, GuiCellOption::AbsoluteOption(dataGrid->columnItemView->GetColumnSize(i)));
						}
					}
				}

				bool DefaultDataGridItemTemplate::IsEditorOpened()
				{
					return currentEditor != nullptr;
				}

				void DefaultDataGridItemTemplate::NotifyOpenEditor(vint column, IDataEditor* editor)
				{
					currentEditor = editor;
					if (currentEditor)
					{
						auto cell = textTable->GetSitedCell(0, column);
						auto* editorBounds = currentEditor->GetTemplate();
						editorBounds->SetFont(GetFont());
						editorBounds->SetContext(GetContext());
						if (editorBounds->GetParent() && editorBounds->GetParent() != cell)
						{
							editorBounds->GetParent()->RemoveChild(editorBounds);
						}
						editorBounds->SetAlignmentToParent(Margin(0, 0, 0, 0));
						cell->AddChild(editorBounds);
						if (auto focusControl = currentEditor->GetTemplate()->GetFocusControl())
						{
							focusControl->SetFocused();
						}
						dataVisualizers[column]->GetTemplate()->SetVisible(false);
					}
				}

				void DefaultDataGridItemTemplate::NotifyCloseEditor()
				{
					if (currentEditor)
					{
						for (vint i = 0; i < dataVisualizers.Count(); i++)
						{
							dataVisualizers[i]->GetTemplate()->SetVisible(true);
						}
						auto composition = currentEditor->GetTemplate();
						if (composition->GetParent())
						{
							composition->GetParent()->RemoveChild(composition);
						}
						currentEditor = nullptr;
					}
				}

				void DefaultDataGridItemTemplate::NotifySelectCell(vint column)
				{
					for (vint i = 0; i < dataVisualizers.Count(); i++)
					{
						dataVisualizers[i]->SetSelected(i == column);
					}
				}

				void DefaultDataGridItemTemplate::NotifyCellEdited()
				{
					for (vint i = 0; i < dataVisualizers.Count(); i++)
					{
						dataVisualizers[i]->BeforeVisualizeCell(listControl->GetItemProvider(), GetIndex(), i);
					}
				}
			}
				
/***********************************************************************
GuiVirtualDataGrid (Editor)
***********************************************************************/

			using namespace list;

			compositions::IGuiAltActionHost* GuiVirtualDataGrid::GetActivatingAltHost()
			{
				if (currentEditor)
				{
					if (auto focusControl = currentEditor->GetTemplate()->GetFocusControl())
					{
						if (auto action = focusControl->QueryTypedService<IGuiAltAction>())
						{
							if (action->IsAltAvailable() && action->IsAltEnabled())
							{
								SetAltComposition(currentEditor->GetTemplate());
								SetAltControl(focusControl, true);
								return this;
							}
						}
					}
				}
				SetAltComposition(nullptr);
				SetAltControl(nullptr, false);
				return GuiVirtualListView::GetActivatingAltHost();
			}

			void GuiVirtualDataGrid::NotifySelectionChanged(bool triggeredByItemContentModified)
			{
				GuiVirtualListView::NotifySelectionChanged(triggeredByItemContentModified);
				if (!skipOnSelectionChanged && !triggeredByItemContentModified)
				{
					vint row = GetSelectedItemIndex();
					if (row == selectedCell.row)
					{
						// do nothing
					}
					else if (row != -1)
					{
						if (selectedCell.row != row && selectedCell.column != -1)
						{
							SelectCell({ row,selectedCell.column }, false);
						}
						else
						{
							SelectCell({ row,0 }, false);
						}
					}
					else
					{
						StopEdit();
						NotifySelectCell(-1, -1);
					}
				}
			}

			void GuiVirtualDataGrid::OnItemModified(vint start, vint count, vint newCount, bool itemReferenceUpdated)
			{
				GuiVirtualListView::OnItemModified(start, count, newCount, itemReferenceUpdated);
				if (!GetItemProvider()->IsEditing())
				{
					StopEdit();
				}
			}

			void GuiVirtualDataGrid::OnStyleInstalled(vint index, ItemStyle* style, bool refreshPropertiesOnly)
			{
				GuiVirtualListView::OnStyleInstalled(index, style, refreshPropertiesOnly);
				if (auto itemStyle = dynamic_cast<DefaultDataGridItemTemplate*>(style))
				{
					if (selectedCell.row == index && selectedCell.column != -1)
					{
						itemStyle->NotifySelectCell(selectedCell.column);
					}
				}
			}

			void GuiVirtualDataGrid::OnStyleUninstalled(ItemStyle* style)
			{
				GuiVirtualListView::OnStyleUninstalled(style);
				if (auto itemStyle = dynamic_cast<DefaultDataGridItemTemplate*>(style))
				{
					if (itemStyle->IsEditorOpened())
					{
						itemStyle->NotifyCloseEditor();
						currentEditor = nullptr;
						currentEditorPos = { -1,-1 };
					}
				}
			}

			void GuiVirtualDataGrid::NotifyCloseEditor()
			{
				if (currentEditorPos.row != -1 && GetArranger())
				{
					auto style = GetArranger()->GetVisibleStyle(currentEditorPos.row);
					if (auto itemStyle = dynamic_cast<DefaultDataGridItemTemplate*>(style))
					{
						itemStyle->NotifyCloseEditor();
					}
				}
			}

			void GuiVirtualDataGrid::NotifySelectCell(vint row, vint column)
			{
				if (selectedCell.row != row || selectedCell.column != column)
				{
					selectedCell = { row, column };
					SelectedCellChanged.Execute(GetNotifyEventArguments());

					auto style = GetArranger()->GetVisibleStyle(row);
					if (auto itemStyle = dynamic_cast<DefaultDataGridItemTemplate*>(style))
					{
						itemStyle->NotifySelectCell(column);
					}
				}
			}

			bool GuiVirtualDataGrid::StartEdit(vint row, vint column)
			{
				StopEdit();
				NotifySelectCell(row, column);

				auto style = GetArranger()->GetVisibleStyle(row);
				if (auto itemStyle = dynamic_cast<DefaultDataGridItemTemplate*>(style))
				{
					if (auto factory = dataGridView->GetCellDataEditorFactory(row, column))
					{
						currentEditorOpeningEditor = true;
						currentEditorPos = { row,column };
						currentEditor = factory->CreateEditor(this);
						if (auto focusControl = currentEditor->GetTemplate()->GetFocusControl())
						{
							focusControl->SetAlt(L"E");
						}
						currentEditor->BeforeEditCell(GetItemProvider(), row, column);
						itemStyle->NotifyOpenEditor(column, currentEditor.Obj());
						currentEditorOpeningEditor = false;
						return true;
					}
				}
				return false;
			}

			void GuiVirtualDataGrid::StopEdit()
			{
				if (GetItemProvider()->IsEditing())
				{
					NotifyCloseEditor();
				}
				else
				{
					if (currentEditorPos != GridPos{-1, -1})
					{
						if (currentEditor)
						{
							NotifyCloseEditor();
						}
					}
				}
				SetAltComposition(nullptr);
				SetAltControl(nullptr, false);
				currentEditor = nullptr;
				currentEditorPos = { -1,-1 };
			}

/***********************************************************************
GuiVirtualDataGrid (IDataGridContext)
***********************************************************************/

			templates::GuiListViewTemplate* GuiVirtualDataGrid::GetListViewControlTemplate()
			{
				return TypedControlTemplateObject(true);
			}

			void GuiVirtualDataGrid::RequestSaveData()
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::list::DefaultTextListItemTemplate::OnBulletSelectedChanged(GuiGraphicsComposition*, GuiEventArgs&)#"
				if (currentEditor && !currentEditorOpeningEditor)
				{
					GuiControl* focusedControl = nullptr;
					if (auto controlHost = GetRelatedControlHost())
					{
						if (auto graphicsHost = controlHost->GetGraphicsHost())
						{
							if (auto focusComposition = graphicsHost->GetFocusedComposition())
							{
								focusedControl = focusComposition->GetRelatedControl();
							}
						}
					}

					GetItemProvider()->PushEditing();
					dataGridView->SetBindingCellValue(currentEditorPos.row, currentEditorPos.column, currentEditor->GetTemplate()->GetCellValue());
					CHECK_ERROR(GetItemProvider()->PopEditing(), ERROR_MESSAGE_PREFIX L"BeginEditListItem and EndEditListItem calls are not paired.");

					auto style = GetArranger()->GetVisibleStyle(currentEditorPos.row);
					if (auto itemStyle = dynamic_cast<DefaultDataGridItemTemplate*>(style))
					{
						itemStyle->NotifyCellEdited();
					}

					if (currentEditor && focusedControl)
					{
						focusedControl->SetFocused();
					}
				}
#undef ERROR_MESSAGE_PREFIX
			}

/***********************************************************************
GuiVirtualDataGrid
***********************************************************************/

			void GuiVirtualDataGrid::OnColumnClicked(compositions::GuiGraphicsComposition* sender, compositions::GuiItemEventArgs& arguments)
			{
				if(dataGridView->IsColumnSortable(arguments.itemIndex))
				{
					switch(columnItemView->GetSortingState(arguments.itemIndex))
					{
					case ColumnSortingState::NotSorted:
						dataGridView->SortByColumn(arguments.itemIndex, true);
						break;
					case ColumnSortingState::Ascending:
						dataGridView->SortByColumn(arguments.itemIndex, false);
						break;
					case ColumnSortingState::Descending:
						dataGridView->SortByColumn(-1, false);
						break;
					}
				}
			}

			void GuiVirtualDataGrid::OnKeyDown(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
				if (selectedCell.row != -1)
				{
					if (arguments.code == VKEY::KEY_RETURN)
					{
						RequestSaveData();
						SelectCell(selectedCell, !currentEditor);
						arguments.handled = true;
						if (!currentEditor)
						{
							SetFocused();
						}
						arguments.handled = true;
					}
					else if (arguments.code == VKEY::KEY_ESCAPE)
					{
						if (currentEditor)
						{
							SelectCell(currentEditorPos, false);
							SetFocused();
							arguments.handled = true;
						}
					}
					else
					{
						vint columnOffset = 0;
						switch (arguments.code)
						{
						case VKEY::KEY_LEFT:
							columnOffset = -1;
							arguments.handled = true;
							break;
						case VKEY::KEY_RIGHT:
							columnOffset = 1;
							arguments.handled = true;
							break;
						default:
							return;
						}

						vint column = selectedCell.column + columnOffset;
						if (column < 0)
						{
							column = 0;
						}
						else if (column >= listViewItemView->GetColumnCount())
						{
							column = listViewItemView->GetColumnCount();
						}
						SelectCell({ selectedCell.row, column }, false);
					}
				}
			}

			void GuiVirtualDataGrid::OnKeyUp(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
			}

			GuiVirtualDataGrid::GuiVirtualDataGrid(theme::ThemeName themeName, list::IItemProvider* _itemProvider)
				:GuiVirtualListView(themeName, _itemProvider)
			{
				listViewItemView = dynamic_cast<IListViewItemView*>(_itemProvider->RequestView(WString::Unmanaged(IListViewItemView::Identifier)));
				columnItemView = dynamic_cast<IColumnItemView*>(_itemProvider->RequestView(WString::Unmanaged(IColumnItemView::Identifier)));
				dataGridView = dynamic_cast<IDataGridView*>(_itemProvider->RequestView(WString::Unmanaged(IDataGridView::Identifier)));

				{
					auto mainProperty = [](const Value&) { return new MainColumnVisualizerTemplate; };
					auto subProperty = [](const Value&) { return new SubColumnVisualizerTemplate; };
					auto focusRectangleProperty = [](const Value&) { return new FocusRectangleVisualizerTemplate; };
					auto cellBorderProperty = [](const Value&) { return new CellBorderVisualizerTemplate; };

					defaultMainColumnVisualizerFactory = 
						Ptr(new DataVisualizerFactory(cellBorderProperty,
							Ptr(new DataVisualizerFactory(focusRectangleProperty,
								Ptr(new DataVisualizerFactory(mainProperty)
						)))));
					defaultSubColumnVisualizerFactory = 
						Ptr(new DataVisualizerFactory(cellBorderProperty,
							Ptr(new DataVisualizerFactory(focusRectangleProperty,
								Ptr(new DataVisualizerFactory(subProperty)
						)))));
				}

				CHECK_ERROR(listViewItemView != nullptr, L"GuiVirtualDataGrid::GuiVirtualDataGrid(IStyleController*, GuiListControl::IItemProvider*)#Missing IListViewItemView from item provider.");
				CHECK_ERROR(columnItemView != nullptr, L"GuiVirtualDataGrid::GuiVirtualDataGrid(IStyleController*, GuiListControl::IItemProvider*)#Missing ListViewColumnItemArranger::IColumnItemView from item provider.");
				CHECK_ERROR(dataGridView != nullptr, L"GuiVirtualDataGrid::GuiVirtualDataGrid(IStyleController*, GuiListControl::IItemProvider*)#Missing IDataGridView from item provider.");

				SetViewToDefault();

				ColumnClicked.AttachMethod(this, &GuiVirtualDataGrid::OnColumnClicked);
				focusableComposition->GetEventReceiver()->keyDown.AttachMethod(this, &GuiVirtualDataGrid::OnKeyDown);
				focusableComposition->GetEventReceiver()->keyUp.AttachMethod(this, &GuiVirtualDataGrid::OnKeyUp);
				SelectedCellChanged.SetAssociatedComposition(boundsComposition);
			}

			GuiVirtualDataGrid::~GuiVirtualDataGrid()
			{
			}

			list::IItemProvider* GuiVirtualDataGrid::GetItemProvider()
			{
				return GuiVirtualListView::GetItemProvider();
			}

			void GuiVirtualDataGrid::SetViewToDefault()
			{
				SetStyleAndArranger(
					[](const Value&) { return new list::DefaultDataGridItemTemplate; },
					Ptr(new list::ListViewColumnItemArranger)
				);
			}

			GridPos GuiVirtualDataGrid::GetSelectedCell()
			{
				return selectedCell;
			}

			Ptr<list::IDataEditor> GuiVirtualDataGrid::GetOpenedEditor()
			{
				return currentEditor;
			}

			bool GuiVirtualDataGrid::SelectCell(const GridPos& value, bool openEditor)
			{
				bool validPos = 0 <= value.row && value.row < GetItemProvider()->Count() && 0 <= value.column && value.column < listViewItemView->GetColumnCount();

				if (validPos && selectedCell == value)
				{
					if (currentEditor && !openEditor)
					{
						StopEdit();
					}
					else if (!currentEditor && openEditor)
					{
						StartEdit(value.row, value.column);
					}
					return currentEditor != nullptr;
				}

				StopEdit();
				if (validPos)
				{
					NotifySelectCell(value.row, value.column);
					if (openEditor)
					{
						EnsureItemVisible(value.row);
						if (GetMultiSelect())
						{
							ClearSelection();
						}
					}
					skipOnSelectionChanged = true;
					SetSelected(value.row, true);
					skipOnSelectionChanged = false;
					if (openEditor)
					{
						return StartEdit(value.row, value.column);
					}
				}
				else
				{
					NotifySelectCell(-1, -1);
					ClearSelection();
				}
				return false;
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\GUIDATAGRIDEXTENSIONS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			namespace list
			{
				using namespace compositions;
				using namespace elements;
				using namespace theme;
				using namespace templates;
				
/***********************************************************************
DataVisualizerBase
***********************************************************************/

				DataVisualizerBase::DataVisualizerBase()
				{
				}

				DataVisualizerBase::~DataVisualizerBase()
				{
					if (visualizerTemplate)
					{
						SafeDeleteComposition(visualizerTemplate);
					}
				}

				IDataVisualizerFactory* DataVisualizerBase::GetFactory()
				{
					return factory;
				}

				templates::GuiGridVisualizerTemplate* DataVisualizerBase::GetTemplate()
				{
					return visualizerTemplate;
				}

				void DataVisualizerBase::NotifyDeletedTemplate()
				{
					visualizerTemplate = nullptr;
				}

				void DataVisualizerBase::BeforeVisualizeCell(list::IItemProvider* itemProvider, vint row, vint column)
				{
					if (auto listViewItemView = dynamic_cast<IListViewItemView*>(dataGridContext->GetItemProvider()->RequestView(WString::Unmanaged(IListViewItemView::Identifier))))
					{
						auto style = dataGridContext->GetListViewControlTemplate();
						visualizerTemplate->SetPrimaryTextColor(style->GetPrimaryTextColor());
						visualizerTemplate->SetSecondaryTextColor(style->GetSecondaryTextColor());
						visualizerTemplate->SetItemSeparatorColor(style->GetItemSeparatorColor());

						visualizerTemplate->SetLargeImage(listViewItemView->GetLargeImage(row));
						visualizerTemplate->SetSmallImage(listViewItemView->GetSmallImage(row));
						visualizerTemplate->SetText(column == 0 ? listViewItemView->GetText(row) : listViewItemView->GetSubItem(row, column - 1));
					}
					if (auto dataGridView = dynamic_cast<IDataGridView*>(dataGridContext->GetItemProvider()->RequestView(WString::Unmanaged(IDataGridView::Identifier))))
					{
						visualizerTemplate->SetRowValue(itemProvider->GetBindingValue(row));
						visualizerTemplate->SetCellValue(dataGridView->GetBindingCellValue(row, column));
					}
				}

				void DataVisualizerBase::SetSelected(bool value)
				{
					if (visualizerTemplate)
					{
						visualizerTemplate->SetSelected(value);
					}
				}

/***********************************************************************
DataVisualizerFactory
***********************************************************************/

				DataVisualizerFactory::ItemTemplate* DataVisualizerFactory::CreateItemTemplate(controls::list::IDataGridContext* dataGridContext)
				{
					ItemTemplate* itemTemplate = templateFactory({});
					CHECK_ERROR(itemTemplate, L"DataVisualizerFactory::CreateItemTemplate(IDataGridContext*)#An instance of GuiGridEditorTemplate is expected.");
					if (decoratedFactory)
					{
						auto childTemplate = decoratedFactory->CreateItemTemplate(dataGridContext);
						childTemplate->SetAlignmentToParent(Margin(0, 0, 0, 0));
						itemTemplate->GetContainerComposition()->AddChild(childTemplate);

#define FORWARD_EVENT(NAME)\
						itemTemplate->NAME##Changed.AttachLambda([=](GuiGraphicsComposition* sender, GuiEventArgs& arguments)\
						{\
							childTemplate->Set##NAME(itemTemplate->Get##NAME());\
						});\

#define FORWARD_EVENT_IMPL(CLASS, TYPE, NAME, VALUE) FORWARD_EVENT(NAME)

						GuiTemplate_PROPERTIES(FORWARD_EVENT_IMPL)
						GuiControlTemplate_PROPERTIES(FORWARD_EVENT_IMPL)
						GuiGridCellTemplate_PROPERTIES(FORWARD_EVENT_IMPL)
						GuiGridVisualizerTemplate_PROPERTIES(FORWARD_EVENT_IMPL)

#undef FORWARD_EVENT_IMPL
#undef FORWARD_EVENT
					}
					return itemTemplate;
				}

				DataVisualizerFactory::DataVisualizerFactory(TemplateProperty<ItemTemplate> _templateFactory, Ptr<DataVisualizerFactory> _decoratedFactory)
					:templateFactory(_templateFactory)
					, decoratedFactory(_decoratedFactory)
				{
				}

				DataVisualizerFactory::~DataVisualizerFactory()
				{
				}

				Ptr<controls::list::IDataVisualizer> DataVisualizerFactory::CreateVisualizer(controls::list::IDataGridContext* dataGridContext)
				{
					auto dataVisualizer = Ptr(new DataVisualizerBase);
					dataVisualizer->factory = this;
					dataVisualizer->dataGridContext = dataGridContext;
					dataVisualizer->visualizerTemplate = CreateItemTemplate(dataGridContext);

					return dataVisualizer;
				}
				
/***********************************************************************
DataEditorBase
***********************************************************************/

				void DataEditorBase::OnCellValueChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					dataGridContext->RequestSaveData();
				}

				DataEditorBase::DataEditorBase()
				{
				}

				DataEditorBase::~DataEditorBase()
				{
					if (editorTemplate)
					{
						SafeDeleteComposition(editorTemplate);
					}
				}

				IDataEditorFactory* DataEditorBase::GetFactory()
				{
					return factory;
				}

				templates::GuiGridEditorTemplate* DataEditorBase::GetTemplate()
				{
					return editorTemplate;
				}

				void DataEditorBase::NotifyDeletedTemplate()
				{
					editorTemplate = nullptr;
				}

				void DataEditorBase::BeforeEditCell(list::IItemProvider* itemProvider, vint row, vint column)
				{
					if (auto listViewItemView = dynamic_cast<IListViewItemView*>(dataGridContext->GetItemProvider()->RequestView(WString::Unmanaged(IListViewItemView::Identifier))))
					{
						auto style = dataGridContext->GetListViewControlTemplate();
						editorTemplate->SetPrimaryTextColor(style->GetPrimaryTextColor());
						editorTemplate->SetSecondaryTextColor(style->GetSecondaryTextColor());
						editorTemplate->SetItemSeparatorColor(style->GetItemSeparatorColor());

						editorTemplate->SetLargeImage(listViewItemView->GetLargeImage(row));
						editorTemplate->SetSmallImage(listViewItemView->GetSmallImage(row));
						editorTemplate->SetText(column == 0 ? listViewItemView->GetText(row) : listViewItemView->GetSubItem(row, column - 1));
					}
					if (auto dataGridView = dynamic_cast<IDataGridView*>(dataGridContext->GetItemProvider()->RequestView(WString::Unmanaged(IDataGridView::Identifier))))
					{
						editorTemplate->SetRowValue(itemProvider->GetBindingValue(row));
						editorTemplate->SetCellValue(dataGridView->GetBindingCellValue(row, column));
					}
					editorTemplate->CellValueChanged.AttachMethod(this, &DataEditorBase::OnCellValueChanged);
				}

				bool DataEditorBase::GetCellValueSaved()
				{
					if (editorTemplate)
					{
						return editorTemplate->GetCellValueSaved();
					}
					return true;
				}

/***********************************************************************
DataEditorFactory
***********************************************************************/

				DataEditorFactory::DataEditorFactory(TemplateProperty<GuiGridEditorTemplate> _templateFactory)
					:templateFactory(_templateFactory)
				{
				}

				DataEditorFactory::~DataEditorFactory()
				{
				}

				Ptr<IDataEditor> DataEditorFactory::CreateEditor(controls::list::IDataGridContext* dataGridContext)
				{
					auto editor = Ptr(new DataEditorBase);
					editor->factory = this;
					editor->dataGridContext = dataGridContext;

					ItemTemplate* itemTemplate = templateFactory({});
					CHECK_ERROR(itemTemplate, L"DataEditorFactory::CreateEditor(IDataGridContext*)#An instance of GuiGridEditorTemplate is expected.");
					editor->editorTemplate = itemTemplate;
					return editor;
				}
				
/***********************************************************************
MainColumnVisualizerTemplate
***********************************************************************/

				void MainColumnVisualizerTemplate::OnTextChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					text->SetText(GetText());
				}

				void MainColumnVisualizerTemplate::OnFontChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					text->SetFont(GetFont());
				}

				void MainColumnVisualizerTemplate::OnTextColorChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					text->SetColor(GetPrimaryTextColor());
				}

				void MainColumnVisualizerTemplate::OnSmallImageChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					auto imageData = GetSmallImage();
					if (imageData)
					{
						image->SetImage(imageData->GetImage(), imageData->GetFrameIndex());
					}
					else
					{
						image->SetImage(nullptr);
					}
				}

				MainColumnVisualizerTemplate::MainColumnVisualizerTemplate()
				{
					GuiTableComposition* table = new GuiTableComposition;
					table->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					table->SetRowsAndColumns(3, 2);
					table->SetRowOption(0, GuiCellOption::PercentageOption(0.5));
					table->SetRowOption(1, GuiCellOption::MinSizeOption());
					table->SetRowOption(2, GuiCellOption::PercentageOption(0.5));
					table->SetColumnOption(0, GuiCellOption::MinSizeOption());
					table->SetColumnOption(1, GuiCellOption::PercentageOption(1.0));
					table->SetCellPadding(2);
					{
						GuiCellComposition* cell = new GuiCellComposition;
						table->AddChild(cell);
						cell->SetSite(1, 0, 1, 1);
						cell->SetPreferredMinSize(Size(16, 16));

						image = GuiImageFrameElement::Create();
						image->SetStretch(true);
						cell->SetOwnedElement(Ptr(image));
					}
					{
						GuiCellComposition* cell = new GuiCellComposition;
						table->AddChild(cell);
						cell->SetSite(0, 1, 3, 1);

						auto textBounds = new GuiBoundsComposition;
						cell->AddChild(textBounds);
						textBounds->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElement);
						textBounds->SetAlignmentToParent(Margin(0, 0, 8, 0));

						text = GuiSolidLabelElement::Create();
						text->SetAlignments(Alignment::Left, Alignment::Center);
						text->SetEllipse(true);
						textBounds->SetOwnedElement(Ptr(text));
					}
					table->SetAlignmentToParent(Margin(0, 0, 0, 0));

					SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					AddChild(table);

					TextChanged.AttachMethod(this, &MainColumnVisualizerTemplate::OnTextChanged);
					FontChanged.AttachMethod(this, &MainColumnVisualizerTemplate::OnFontChanged);
					PrimaryTextColorChanged.AttachMethod(this, &MainColumnVisualizerTemplate::OnTextColorChanged);
					SmallImageChanged.AttachMethod(this, &MainColumnVisualizerTemplate::OnSmallImageChanged);

					TextChanged.Execute(compositions::GuiEventArgs(this));
					FontChanged.Execute(compositions::GuiEventArgs(this));
					PrimaryTextColorChanged.Execute(compositions::GuiEventArgs(this));
					SmallImageChanged.Execute(compositions::GuiEventArgs(this));
				}

				MainColumnVisualizerTemplate::~MainColumnVisualizerTemplate()
				{
				}
				
/***********************************************************************
SubColumnVisualizerTemplate
***********************************************************************/

				void SubColumnVisualizerTemplate::OnTextChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					text->SetText(GetText());
				}

				void SubColumnVisualizerTemplate::OnFontChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					text->SetFont(GetFont());
				}

				void SubColumnVisualizerTemplate::OnTextColorChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					text->SetColor(GetSecondaryTextColor());
				}

				void SubColumnVisualizerTemplate::Initialize(bool fixTextColor)
				{
					SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

					auto textBounds = new GuiBoundsComposition;
					AddChild(textBounds);
					textBounds->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElement);
					textBounds->SetAlignmentToParent(Margin(8, 0, 8, 0));

					text = GuiSolidLabelElement::Create();
					text->SetVerticalAlignment(Alignment::Center);
					text->SetEllipse(true);
					textBounds->SetOwnedElement(Ptr(text));

					TextChanged.AttachMethod(this, &SubColumnVisualizerTemplate::OnTextChanged);
					FontChanged.AttachMethod(this, &SubColumnVisualizerTemplate::OnFontChanged);
					if (!fixTextColor)
					{
						SecondaryTextColorChanged.AttachMethod(this, &SubColumnVisualizerTemplate::OnTextColorChanged);
					}

					TextChanged.Execute(compositions::GuiEventArgs(this));
					FontChanged.Execute(compositions::GuiEventArgs(this));
					if (!fixTextColor)
					{
						SecondaryTextColorChanged.Execute(compositions::GuiEventArgs(this));
					}
				}

				SubColumnVisualizerTemplate::SubColumnVisualizerTemplate(bool fixTextColor)
				{
					Initialize(fixTextColor);
				}

				SubColumnVisualizerTemplate::SubColumnVisualizerTemplate()
				{
					Initialize(false);
				}

				SubColumnVisualizerTemplate::~SubColumnVisualizerTemplate()
				{
				}
				
/***********************************************************************
HyperlinkVisualizerTemplate
***********************************************************************/

				void HyperlinkVisualizerTemplate::label_MouseEnter(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					FontProperties font = text->GetFont();
					font.underline = true;
					text->SetFont(font);
				}

				void HyperlinkVisualizerTemplate::label_MouseLeave(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					FontProperties font = text->GetFont();
					font.underline = false;
					text->SetFont(font);
				}

				HyperlinkVisualizerTemplate::HyperlinkVisualizerTemplate()
					:SubColumnVisualizerTemplate(true)
				{
					text->SetColor(Color(0, 0, 255));
					text->SetEllipse(true);
					GetEventReceiver()->mouseEnter.AttachMethod(this, &HyperlinkVisualizerTemplate::label_MouseEnter);
					GetEventReceiver()->mouseLeave.AttachMethod(this, &HyperlinkVisualizerTemplate::label_MouseLeave);
					SetAssociatedCursor(GetCurrentController()->ResourceService()->GetSystemCursor(INativeCursor::Hand));
				}

				HyperlinkVisualizerTemplate::~HyperlinkVisualizerTemplate()
				{
				}
				
/***********************************************************************
CellBorderVisualizerTemplate
***********************************************************************/

				void FocusRectangleVisualizerTemplate::OnSelectedChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					focusComposition->SetVisible(GetSelected());
				}

				FocusRectangleVisualizerTemplate::FocusRectangleVisualizerTemplate()
				{
					SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

					focusComposition = new GuiBoundsComposition();
					{
						auto focus = Ptr(GuiFocusRectangleElement::Create());
						focusComposition->SetOwnedElement(focus);
						focusComposition->SetAlignmentToParent(Margin(1, 1, 1, 1));
					}
					auto container = new GuiBoundsComposition();
					{
						container->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
						container->SetAlignmentToParent(Margin(2, 2, 2, 2));
					}

					AddChild(focusComposition);
					AddChild(container);
					SetContainerComposition(container);

					SelectedChanged.AttachMethod(this, &FocusRectangleVisualizerTemplate::OnSelectedChanged);
					SelectedChanged.Execute(compositions::GuiEventArgs(this));
				}

				FocusRectangleVisualizerTemplate::~FocusRectangleVisualizerTemplate()
				{
				}
				
/***********************************************************************
CellBorderVisualizerTemplate
***********************************************************************/

				void CellBorderVisualizerTemplate::OnItemSeparatorColorChanged(GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					border1->SetColor(GetItemSeparatorColor());
					border2->SetColor(GetItemSeparatorColor());
				}

				CellBorderVisualizerTemplate::CellBorderVisualizerTemplate()
				{
					SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

					auto bounds1 = new GuiBoundsComposition;
					{
						border1 = GuiSolidBorderElement::Create();
						bounds1->SetOwnedElement(Ptr(border1));
						bounds1->SetAlignmentToParent(Margin(-1, 0, 0, 0));
					}
					auto bounds2 = new GuiBoundsComposition;
					{
						border2 = GuiSolidBorderElement::Create();
						bounds2->SetOwnedElement(Ptr(border2));
						bounds2->SetAlignmentToParent(Margin(0, -1, 0, 0));
					}
					auto container = new GuiBoundsComposition();
					{
						container->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
						container->SetAlignmentToParent(Margin(0, 0, 1, 1));
					}

					AddChild(bounds1);
					AddChild(bounds2);
					AddChild(container);
					SetContainerComposition(container);

					ItemSeparatorColorChanged.AttachMethod(this, &CellBorderVisualizerTemplate::OnItemSeparatorColorChanged);
					ItemSeparatorColorChanged.Execute(compositions::GuiEventArgs(this));
				}

				CellBorderVisualizerTemplate::~CellBorderVisualizerTemplate()
				{
				}
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\GUILISTCONTROLITEMARRANGERS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace collections;
			using namespace elements;
			using namespace compositions;

			namespace list
			{

/***********************************************************************
RangedItemArrangerBase (ItemSource)
***********************************************************************/

				class ArrangerItemSource : public Object, public virtual description::IValueObservableList
				{
				protected:
					list::IItemProvider*				itemProvider = nullptr;

				public:
					ArrangerItemSource(list::IItemProvider* _itemProvider)
						: itemProvider(_itemProvider)
					{
					}

					vint GetCount() override
					{
						return itemProvider->Count();
					}

					description::Value Get(vint index) override
					{
						return itemProvider->GetBindingValue(index);
					}

					Ptr<description::IValueEnumerator>	CreateEnumerator()										override { CHECK_FAIL(L"ArrangerItemSource::CreateEnumerator should not be called."); }
					bool								Contains(const description::Value& value)				override { CHECK_FAIL(L"ArrangerItemSource::Contains should not be called."); }
					vint								IndexOf(const description::Value& value)				override { CHECK_FAIL(L"ArrangerItemSource::IndexOf should not be called."); }

					void								Set(vint index, const description::Value& value)		override { CHECK_FAIL(L"ArrangerItemSource::Set should not be called."); }
					vint								Add(const description::Value& value)					override { CHECK_FAIL(L"ArrangerItemSource::Add should not be called."); }
					vint								Insert(vint index, const description::Value& value)		override { CHECK_FAIL(L"ArrangerItemSource::Insert should not be called."); }
					bool								Remove(const description::Value& value)					override { CHECK_FAIL(L"ArrangerItemSource::Remove should not be called."); }
					bool								RemoveAt(vint index)									override { CHECK_FAIL(L"ArrangerItemSource::RemoveAt should not be called."); }
					void								Clear()													override { CHECK_FAIL(L"ArrangerItemSource::Clear should not be called."); }
				};

/***********************************************************************
RangedItemArrangerBase
***********************************************************************/

				void RangedItemArrangerBase::OnViewLocationChanged(compositions::GuiGraphicsComposition* composition, compositions::GuiEventArgs& arguments)
				{
					if (callback)
					{
						callback->SetViewLocation(repeat->GetViewLocation());
					}
				}

				void RangedItemArrangerBase::OnTotalSizeChanged(compositions::GuiGraphicsComposition* composition, compositions::GuiEventArgs& arguments)
				{
					if (callback)
					{
						callback->OnTotalSizeChanged();
					}
				}

				void RangedItemArrangerBase::OnAdoptedSizeInvalidated(compositions::GuiGraphicsComposition* composition, compositions::GuiEventArgs& arguments)
				{
					if (callback)
					{
						callback->OnAdoptedSizeChanged();
					}
				}

				RangedItemArrangerBase::RangedItemArrangerBase(compositions::GuiVirtualRepeatCompositionBase* _repeat)
					: repeat(_repeat)
				{
					repeat->ViewLocationChanged.AttachMethod(this, &RangedItemArrangerBase::OnViewLocationChanged);
					repeat->TotalSizeChanged.AttachMethod(this, &RangedItemArrangerBase::OnTotalSizeChanged);
					repeat->AdoptedSizeInvalidated.AttachMethod(this, &RangedItemArrangerBase::OnAdoptedSizeInvalidated);
				}

				RangedItemArrangerBase::~RangedItemArrangerBase()
				{
					SafeDeleteComposition(repeat);
				}

				void RangedItemArrangerBase::OnAttached(list::IItemProvider* provider)
				{
					itemProvider = provider;
					if (provider)
					{
						itemSource = Ptr(new ArrangerItemSource(provider));
						repeat->SetItemSource(itemSource);
					}
					else
					{
						repeat->SetItemSource(nullptr);
						itemSource = nullptr;
					}
				}

				void RangedItemArrangerBase::OnItemModified(vint start, vint count, vint newCount, bool itemReferenceUpdated)
				{
					if (itemSource && itemReferenceUpdated)
					{
						itemSource->ItemChanged(start, count, newCount);
					}
				}

				void RangedItemArrangerBase::AttachListControl(GuiListControl* value)
				{
					listControl = value;
					repeat->SetAxis(Ptr(listControl->GetAxis()));
				}

				void RangedItemArrangerBase::DetachListControl()
				{
					repeat->SetAxis(nullptr);
					listControl = nullptr;
				}

				GuiListControl::IItemArrangerCallback* RangedItemArrangerBase::GetCallback()
				{
					return callback;
				}

				void RangedItemArrangerBase::SetCallback(GuiListControl::IItemArrangerCallback* value)
				{
					if (callback != value)
					{
						if (callback)
						{
							repeat->GetParent()->RemoveChild(repeat);
							repeat->SetItemTemplate({});
						}
						callback = value;
						if (callback)
						{
							callback->GetContainerComposition()->AddChild(repeat);
							repeat->SetItemTemplate([](const description::Value&)->templates::GuiTemplate*
							{
								CHECK_FAIL(L"This function should not be called, it is used to enable the virtual repeat composition.");
							});
						}
					}
				}

				Size RangedItemArrangerBase::GetTotalSize()
				{
					if (callback && repeat)
					{
						return repeat->GetTotalSize();
					}
					return Size(0, 0);
				}

				GuiListControl::ItemStyle* RangedItemArrangerBase::GetVisibleStyle(vint itemIndex)
				{
					auto bounds = repeat->GetVisibleStyle(itemIndex);
					return bounds ? callback->GetItem(bounds) : nullptr;
				}

				vint RangedItemArrangerBase::GetVisibleIndex(GuiListControl::ItemStyle* style)
				{
					auto bounds = callback->GetItemBounds(style);
					return repeat->GetVisibleIndex(bounds);
				}

				void RangedItemArrangerBase::ReloadVisibleStyles()
				{
					if (repeat) repeat->ResetLayout(true);
				}

				void RangedItemArrangerBase::OnViewChanged(Rect bounds)
				{
					repeat->SetViewLocation(bounds.LeftTop());
					repeat->SetExpectedBounds(Rect({ 0,0 }, bounds.GetSize()));
				}

				vint RangedItemArrangerBase::FindItemByVirtualKeyDirection(vint itemIndex, compositions::KeyDirection key)
				{
					return repeat->FindItemByVirtualKeyDirection(itemIndex, key);
				}

				GuiListControl::EnsureItemVisibleResult RangedItemArrangerBase::EnsureItemVisible(vint itemIndex)
				{
					switch (repeat->EnsureItemVisible(itemIndex))
					{
					case VirtualRepeatEnsureItemVisibleResult::Moved:
						return GuiListControl::EnsureItemVisibleResult::Moved;
					case VirtualRepeatEnsureItemVisibleResult::NotMoved:
						return GuiListControl::EnsureItemVisibleResult::NotMoved;
					default:
						return GuiListControl::EnsureItemVisibleResult::ItemNotExists;
					}
				}

				Size RangedItemArrangerBase::GetAdoptedSize(Size expectedSize)
				{
					return repeat->GetAdoptedSize(expectedSize);
				}

/***********************************************************************
VirtualRepeatRangedItemArrangerBase
***********************************************************************/

				FreeHeightItemArranger::FreeHeightItemArranger()
				{
				}

				FreeHeightItemArranger::~FreeHeightItemArranger()
				{
				}

				FixedHeightItemArranger::FixedHeightItemArranger()
				{
				}

				FixedHeightItemArranger::~FixedHeightItemArranger()
				{
				}

				FixedSizeMultiColumnItemArranger::FixedSizeMultiColumnItemArranger()
				{
				}

				FixedSizeMultiColumnItemArranger::~FixedSizeMultiColumnItemArranger()
				{
				}

				FixedHeightMultiColumnItemArranger::FixedHeightMultiColumnItemArranger()
				{
				}

				FixedHeightMultiColumnItemArranger::~FixedHeightMultiColumnItemArranger()
				{
				}
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\GUILISTCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace collections;
			using namespace elements;
			using namespace compositions;

/***********************************************************************
GuiListControl::ItemCallback
***********************************************************************/

			GuiListControl::ItemStyleRecord GuiListControl::ItemCallback::InstallStyle(ItemStyle* style, vint itemIndex)
			{
				templates::GuiTemplate* bounds = style;
				if (listControl->GetDisplayItemBackground())
				{
					style->SetAlignmentToParent(Margin(0, 0, 0, 0));

					auto backgroundButton = new GuiSelectableButton(theme::ThemeName::ListItemBackground);
					if (auto backgroundStyle = listControl->TypedControlTemplateObject(true)->GetBackgroundTemplate())
					{
						backgroundButton->SetControlTemplate(backgroundStyle);
					}
					backgroundButton->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
					backgroundButton->SetAutoFocus(false);
					backgroundButton->SetAutoSelection(false);
					backgroundButton->SetSelected(style->GetSelected());
					backgroundButton->GetContainerComposition()->AddChild(style);

					bounds = new templates::GuiTemplate;
					bounds->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					bounds->AddChild(backgroundButton->GetBoundsComposition());
					
					style->SelectedChanged.AttachLambda([=](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
					{
						backgroundButton->SetSelected(style->GetSelected());
					});
				}

				listControl->OnStyleInstalled(itemIndex, style, false);
				return { style,bounds };
			}

			GuiListControl::ItemStyleRecord GuiListControl::ItemCallback::UninstallStyle(vint index)
			{
				auto style = installedStyles.Keys()[index];
				auto bounds = installedStyles.Values()[index];
				listControl->OnStyleUninstalled(style);
				return { style,bounds };
			}

			GuiListControl::ItemCallback::ItemCallback(GuiListControl* _listControl)
				:listControl(_listControl)
			{
			}

			GuiListControl::ItemCallback::~ItemCallback()
			{
				ClearCache();
			}

			void GuiListControl::ItemCallback::ClearCache()
			{
				// TODO: (enumerable) foreach:indexed
				for (vint i = 0; i < installedStyles.Count(); i++)
				{
					auto [style, bounds] = UninstallStyle(i);
					SafeDeleteComposition(bounds);
				}
				installedStyles.Clear();
			}

			void GuiListControl::ItemCallback::OnAttached(list::IItemProvider* provider)
			{
				itemProvider = provider;
			}

			void GuiListControl::ItemCallback::OnItemModified(vint start, vint count, vint newCount, bool itemReferenceUpdated)
			{
				listControl->OnItemModified(start, count, newCount, itemReferenceUpdated);
			}

			GuiListControl::ItemStyle* GuiListControl::ItemCallback::CreateItem(vint itemIndex)
			{
#define ERROR_MESSAGE_PREFIX L"GuiListControl::ItemCallback::RequestItem(vint)#"
				CHECK_ERROR(0 <= itemIndex && itemIndex < itemProvider->Count(), ERROR_MESSAGE_PREFIX L"Index out of range.");
				CHECK_ERROR(listControl->itemStyleProperty, ERROR_MESSAGE_PREFIX L"SetItemTemplate function should be called before adding items to the list control.");

				auto style = listControl->itemStyleProperty(itemProvider->GetBindingValue(itemIndex));
				auto record = InstallStyle(style, itemIndex);
				installedStyles.Add(record);
				return style;
#undef ERROR_MESSAGE_PREFIX
			}

			GuiListControl::ItemStyleBounds* GuiListControl::ItemCallback::GetItemBounds(ItemStyle * style)
			{
#define ERROR_MESSAGE_PREFIX L"GuiListControl::ItemCallback::GetItemBounds(GuiListItemTemplate*)#The style is not created from CreateItem."
				vint index = installedStyles.Keys().IndexOf(style);
				CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX);

				return installedStyles.Values()[index];
#undef ERROR_MESSAGE_PREFIX
			}

			GuiListControl::ItemStyle* GuiListControl::ItemCallback::GetItem(ItemStyleBounds* bounds)
			{
#define ERROR_MESSAGE_PREFIX L"GuiListControl::ItemCallback::GetItem(GuiTemplate*)#The bounds is not created from CreateItem."
				auto style = dynamic_cast<ItemStyle*>(bounds);
				if (style) return style;

				CHECK_ERROR(bounds->Children().Count() == 1, ERROR_MESSAGE_PREFIX);
				auto backgroundButton = dynamic_cast<GuiSelectableButton*>(bounds->Children()[0]->GetAssociatedControl());
				CHECK_ERROR(backgroundButton != nullptr, ERROR_MESSAGE_PREFIX);
				CHECK_ERROR(backgroundButton->GetContainerComposition()->Children().Count() == 1, ERROR_MESSAGE_PREFIX);
				style = dynamic_cast<ItemStyle*>(backgroundButton->GetContainerComposition()->Children()[0]);
				CHECK_ERROR(style != nullptr, ERROR_MESSAGE_PREFIX);

				vint index = installedStyles.Keys().IndexOf(style);
				CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX);
				CHECK_ERROR(installedStyles.Values()[index] == bounds, ERROR_MESSAGE_PREFIX);
				return style;
#undef ERROR_MESSAGE_PREFIX
			}

			void GuiListControl::ItemCallback::ReleaseItem(ItemStyle* style)
			{
#define ERROR_MESSAGE_PREFIX L"GuiListControl::ItemCallback::GetItemBounds(GuiListItemTemplate*)#The style is not created from CreateItem."
				vint index = installedStyles.Keys().IndexOf(style);
				CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX);

				auto bounds = UninstallStyle(index).value;
				installedStyles.Remove(style);
				SafeDeleteComposition(bounds);
#undef ERROR_MESSAGE_PREFIX
			}

			void GuiListControl::ItemCallback::SetViewLocation(Point value)
			{
				listControl->SetViewPosition(value);
			}

			compositions::GuiGraphicsComposition* GuiListControl::ItemCallback::GetContainerComposition()
			{
				return listControl->GetContainerComposition();
			}

			void GuiListControl::ItemCallback::OnTotalSizeChanged()
			{
				listControl->CalculateView();
			}

			void GuiListControl::ItemCallback::OnAdoptedSizeChanged()
			{
				listControl->AdoptedSizeInvalidated.Execute(listControl->GetNotifyEventArguments());
			}

/***********************************************************************
GuiListControl
***********************************************************************/

			void GuiListControl::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiListControl::AfterControlTemplateInstalled_(bool initialize)
			{
				if (itemArranger)
				{
					itemArranger->ReloadVisibleStyles();
					CalculateView();
				}
			}

			void GuiListControl::OnItemModified(vint start, vint count, vint newCount, bool itemReferenceUpdated)
			{
				// this function is executed before RangedItemArrangerBase::OnItemModified
				// but we only handle itemReferenceUpdated==false
				// so RangedItemArrangerBase::GetVisibleStyle is good here
				// even it is possible that the style object will be replaced later
				// OnStyleInstalled will be executed on affected style objects anyway
				if (!itemReferenceUpdated && itemArranger && count == newCount)
				{
					for (vint i = 0; i < newCount; i++)
					{
						vint index = start + i;
						if (auto style = itemArranger->GetVisibleStyle(index))
						{
							OnStyleInstalled(index, style, true);
						}
					}
				}
			}

			void GuiListControl::OnStyleInstalled(vint itemIndex, ItemStyle* style, bool refreshPropertiesOnly)
			{
				style->SetFont(GetDisplayFont());
				style->SetContext(GetContext());
				style->SetText(itemProvider->GetTextValue(itemIndex));
				style->SetVisuallyEnabled(GetVisuallyEnabled());
				style->SetSelected(false);
				style->SetIndex(itemIndex);
				style->SetAssociatedListControl(this);

				if (!refreshPropertiesOnly)
				{
					AttachItemEvents(style);
				}
			}

			void GuiListControl::OnStyleUninstalled(ItemStyle* style)
			{
				DetachItemEvents(style);
			}

			void GuiListControl::OnRenderTargetChanged(elements::IGuiGraphicsRenderTarget* renderTarget)
			{
				SetStyleAndArranger(itemStyleProperty, itemArranger);
				GuiScrollView::OnRenderTargetChanged(renderTarget);
			}

			void GuiListControl::OnBeforeReleaseGraphicsHost()
			{
				GuiScrollView::OnBeforeReleaseGraphicsHost();
				SetStyleAndArranger({}, nullptr);
			}

			Size GuiListControl::QueryFullSize()
			{
				fullSize = itemArranger ? itemArranger->GetTotalSize() : Size(0, 0);
				return fullSize;
			}

			void GuiListControl::UpdateView(Rect viewBounds)
			{
				if (itemArranger)
				{
					itemArranger->OnViewChanged(viewBounds);
				}
			}

			void GuiListControl::OnBoundsMouseButtonDown(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
			{
				if(GetVisuallyEnabled())
				{
					SetFocused();
				}
			}

			void GuiListControl::SetStyleAndArranger(ItemStyleProperty styleProperty, Ptr<IItemArranger> arranger)
			{
				if (itemArranger)
				{
					itemProvider->DetachCallback(itemArranger.Obj());
					itemArranger->DetachListControl();
					itemArranger->SetCallback(nullptr);
				}
				callback->ClearCache();

				itemStyleProperty = styleProperty;
				itemArranger = arranger;

				if (itemArranger)
				{
					itemArranger->SetCallback(callback.Obj());
					itemArranger->AttachListControl(this);
					itemProvider->AttachCallback(itemArranger.Obj());
				}

				if (auto scroll = GetVerticalScroll())
				{
					scroll->SetPosition(0);
				}
				if (auto scroll = GetHorizontalScroll())
				{
					scroll->SetPosition(0);
				}
				CalculateView();
			}

			void GuiListControl::UpdateDisplayFont()
			{
				GuiControl::UpdateDisplayFont();
				for (auto style : visibleStyles.Keys())
				{
					style->SetFont(GetDisplayFont());
				}
			}

			void GuiListControl::OnVisuallyEnabledChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				for (auto style : visibleStyles.Keys())
				{
					style->SetVisuallyEnabled(GetVisuallyEnabled());
				}
			}

			void GuiListControl::OnContextChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				for (auto style : visibleStyles.Keys())
				{
					style->SetContext(GetContext());
				}
			}

			void GuiListControl::OnItemMouseEvent(compositions::GuiItemMouseEvent& itemEvent, ItemStyle* style, compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
			{
				if (itemArranger && GetVisuallyEnabled())
				{
					vint itemIndex = itemArranger->GetVisibleIndex(style);
					if (itemIndex != -1)
					{
						GuiItemMouseEventArgs redirectArguments;
						(GuiMouseEventArgs&)redirectArguments = arguments;
						redirectArguments.compositionSource = boundsComposition;
						redirectArguments.eventSource = boundsComposition;
						redirectArguments.itemIndex = itemIndex;
						itemEvent.Execute(redirectArguments);
						arguments = redirectArguments;
					}
				}
			}

			void GuiListControl::OnItemNotifyEvent(compositions::GuiItemNotifyEvent& itemEvent, ItemStyle* style, compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (itemArranger && GetVisuallyEnabled())
				{
					vint itemIndex = itemArranger->GetVisibleIndex(style);
					if (itemIndex != -1)
					{
						GuiItemEventArgs redirectArguments;
						(GuiEventArgs&)redirectArguments = arguments;
						redirectArguments.compositionSource = boundsComposition;
						redirectArguments.eventSource = boundsComposition;
						redirectArguments.itemIndex = itemIndex;
						itemEvent.Execute(redirectArguments);
						arguments = redirectArguments;
					}
				}
			}

#define ATTACH_ITEM_MOUSE_EVENT(EVENTNAME, ITEMEVENTNAME)\
					{\
						helper->EVENTNAME##Handler = style->GetEventReceiver()->EVENTNAME.AttachFunction(\
							[this, style](GuiGraphicsComposition* sender, GuiMouseEventArgs& args){ OnItemMouseEvent(ITEMEVENTNAME, style, sender, args); }\
							);\
					}\

#define ATTACH_ITEM_NOTIFY_EVENT(EVENTNAME, ITEMEVENTNAME)\
					{\
						helper->EVENTNAME##Handler = style->GetEventReceiver()->EVENTNAME.AttachFunction(\
							[this, style](GuiGraphicsComposition* sender, GuiEventArgs& args){ OnItemNotifyEvent(ITEMEVENTNAME, style, sender, args); }\
							);\
					}\

			void GuiListControl::AttachItemEvents(ItemStyle* style)
			{
				vint index=visibleStyles.Keys().IndexOf(style);
				if(index==-1)
				{
					auto helper=Ptr(new VisibleStyleHelper);
					visibleStyles.Add(style, helper);

					ATTACH_ITEM_MOUSE_EVENT(leftButtonDown, ItemLeftButtonDown);
					ATTACH_ITEM_MOUSE_EVENT(leftButtonUp, ItemLeftButtonUp);
					ATTACH_ITEM_MOUSE_EVENT(leftButtonDoubleClick, ItemLeftButtonDoubleClick);
					ATTACH_ITEM_MOUSE_EVENT(middleButtonDown, ItemMiddleButtonDown);
					ATTACH_ITEM_MOUSE_EVENT(middleButtonUp, ItemMiddleButtonUp);
					ATTACH_ITEM_MOUSE_EVENT(middleButtonDoubleClick, ItemMiddleButtonDoubleClick);
					ATTACH_ITEM_MOUSE_EVENT(rightButtonDown, ItemRightButtonDown);
					ATTACH_ITEM_MOUSE_EVENT(rightButtonUp, ItemRightButtonUp);
					ATTACH_ITEM_MOUSE_EVENT(rightButtonDoubleClick, ItemRightButtonDoubleClick);
					ATTACH_ITEM_MOUSE_EVENT(mouseMove, ItemMouseMove);
					ATTACH_ITEM_NOTIFY_EVENT(mouseEnter, ItemMouseEnter);
					ATTACH_ITEM_NOTIFY_EVENT(mouseLeave, ItemMouseLeave);
				}
			}

#undef ATTACH_ITEM_MOUSE_EVENT
#undef ATTACH_ITEM_NOTIFY_EVENT

#define DETACH_ITEM_EVENT(EVENTNAME) style->GetEventReceiver()->EVENTNAME.Detach(helper->EVENTNAME##Handler)

			void GuiListControl::DetachItemEvents(ItemStyle* style)
			{
				vint index=visibleStyles.Keys().IndexOf(style);
				if(index!=-1)
				{
					Ptr<VisibleStyleHelper> helper=visibleStyles.Values().Get(index);
					visibleStyles.Remove(style);
					
					DETACH_ITEM_EVENT(leftButtonDown);
					DETACH_ITEM_EVENT(leftButtonUp);
					DETACH_ITEM_EVENT(leftButtonDoubleClick);
					DETACH_ITEM_EVENT(middleButtonDown);
					DETACH_ITEM_EVENT(middleButtonUp);
					DETACH_ITEM_EVENT(middleButtonDoubleClick);
					DETACH_ITEM_EVENT(rightButtonDown);
					DETACH_ITEM_EVENT(rightButtonUp);
					DETACH_ITEM_EVENT(rightButtonDoubleClick);
					DETACH_ITEM_EVENT(mouseMove);
					DETACH_ITEM_EVENT(mouseEnter);
					DETACH_ITEM_EVENT(mouseLeave);
				}
			}

#undef DETACH_ITEM_EVENT

			GuiListControl::GuiListControl(theme::ThemeName themeName, list::IItemProvider* _itemProvider, bool acceptFocus)
				:GuiScrollView(themeName)
				, itemProvider(_itemProvider)
			{
				ContextChanged.AttachMethod(this, &GuiListControl::OnContextChanged);
				VisuallyEnabledChanged.AttachMethod(this, &GuiListControl::OnVisuallyEnabledChanged);

				ItemTemplateChanged.SetAssociatedComposition(boundsComposition);
				ArrangerChanged.SetAssociatedComposition(boundsComposition);
				AxisChanged.SetAssociatedComposition(boundsComposition);
				AdoptedSizeInvalidated.SetAssociatedComposition(boundsComposition);

				ItemLeftButtonDown.SetAssociatedComposition(boundsComposition);
				ItemLeftButtonUp.SetAssociatedComposition(boundsComposition);
				ItemLeftButtonDoubleClick.SetAssociatedComposition(boundsComposition);
				ItemMiddleButtonDown.SetAssociatedComposition(boundsComposition);
				ItemMiddleButtonUp.SetAssociatedComposition(boundsComposition);
				ItemMiddleButtonDoubleClick.SetAssociatedComposition(boundsComposition);
				ItemRightButtonDown.SetAssociatedComposition(boundsComposition);
				ItemRightButtonUp.SetAssociatedComposition(boundsComposition);
				ItemRightButtonDoubleClick.SetAssociatedComposition(boundsComposition);
				ItemMouseMove.SetAssociatedComposition(boundsComposition);
				ItemMouseEnter.SetAssociatedComposition(boundsComposition);
				ItemMouseLeave.SetAssociatedComposition(boundsComposition);

				callback = Ptr(new ItemCallback(this));
				itemProvider->AttachCallback(callback.Obj());
				axis = Ptr(new GuiDefaultAxis);

				if (acceptFocus)
				{
					boundsComposition->GetEventReceiver()->leftButtonDown.AttachMethod(this, &GuiListControl::OnBoundsMouseButtonDown);
					boundsComposition->GetEventReceiver()->middleButtonDown.AttachMethod(this, &GuiListControl::OnBoundsMouseButtonDown);
					boundsComposition->GetEventReceiver()->rightButtonDown.AttachMethod(this, &GuiListControl::OnBoundsMouseButtonDown);
					SetFocusableComposition(boundsComposition);
				}
			}

			GuiListControl::~GuiListControl()
			{
				if(itemArranger)
				{
					itemProvider->DetachCallback(itemArranger.Obj());
				}
				callback->ClearCache();
				itemStyleProperty = {};
				itemArranger = nullptr;
			}

			list::IItemProvider* GuiListControl::GetItemProvider()
			{
				return itemProvider.Obj();
			}

			GuiListControl::ItemStyleProperty GuiListControl::GetItemTemplate()
			{
				return itemStyleProperty;
			}

			void GuiListControl::SetItemTemplate(ItemStyleProperty value)
			{
				SetStyleAndArranger(value, itemArranger);
				ItemTemplateChanged.Execute(GetNotifyEventArguments());
			}

			GuiListControl::IItemArranger* GuiListControl::GetArranger()
			{
				return itemArranger.Obj();
			}

			void GuiListControl::SetArranger(Ptr<IItemArranger> value)
			{
				SetStyleAndArranger(itemStyleProperty, value);
				ArrangerChanged.Execute(GetNotifyEventArguments());
			}

			compositions::IGuiAxis* GuiListControl::GetAxis()
			{
				return axis.Obj();
			}

			void GuiListControl::SetAxis(Ptr<compositions::IGuiAxis> value)
			{
				Ptr<IGuiAxis> old = axis;
				axis = value;
				SetStyleAndArranger(itemStyleProperty, itemArranger);
				AxisChanged.Execute(GetNotifyEventArguments());
			}

			bool GuiListControl::EnsureItemVisible(vint itemIndex)
			{
				if (itemIndex < 0 || itemIndex >= itemProvider->Count())
				{
					return false;
				}

				if (!itemArranger) return false;
				auto result = itemArranger->EnsureItemVisible(itemIndex);
				if (result == EnsureItemVisibleResult::Moved)
				{
					if (auto host = GetBoundsComposition()->GetRelatedGraphicsHost())
					{
						auto flag = GetDisposedFlag();
						host->InvokeAfterRendering([=, this]()
						{
							if (!flag->IsDisposed())
							{
								EnsureItemVisible(itemIndex);
							}
						}, { this,0 });
					}
				}
				return result != EnsureItemVisibleResult::ItemNotExists;
			}

			Size GuiListControl::GetAdoptedSize(Size expectedSize)
			{
				if (itemArranger)
				{
					Size controlSize = boundsComposition->GetCachedBounds().GetSize();
					Size viewSize = containerComposition->GetCachedBounds().GetSize();
					vint dx = controlSize.x - viewSize.x;
					vint dy = controlSize.y - viewSize.y;
					if (dx < 0) dx = 0;
					if (dy < 0) dy = 0;

					auto hscroll = GetHorizontalScroll();
					auto vscroll = GetVerticalScroll();

					if (!vscroll || vscroll->GetBoundsComposition()->GetEventuallyVisible())
					{
						if (adoptedSizeDiffWithScroll.x < dx) adoptedSizeDiffWithScroll.x = dx;
					}
					if (!vscroll || !vscroll->GetBoundsComposition()->GetEventuallyVisible())
					{
						if (adoptedSizeDiffWithoutScroll.x < dx) adoptedSizeDiffWithoutScroll.x = dx;
					}

					if (!hscroll || hscroll->GetBoundsComposition()->GetEventuallyVisible())
					{
						if (adoptedSizeDiffWithScroll.y < dy) adoptedSizeDiffWithScroll.y = dy;
					}
					if (!hscroll || !hscroll->GetBoundsComposition()->GetEventuallyVisible())
					{
						if (adoptedSizeDiffWithoutScroll.y < dy) adoptedSizeDiffWithoutScroll.y = dy;
					}

					vint x = adoptedSizeDiffWithoutScroll.x != -1 ? adoptedSizeDiffWithoutScroll.x : adoptedSizeDiffWithScroll.x;
					vint y = adoptedSizeDiffWithoutScroll.y != -1 ? adoptedSizeDiffWithoutScroll.y : adoptedSizeDiffWithScroll.y;

					Size expectedViewSize(expectedSize.x - x, expectedSize.y - y);
					Size adoptedViewSize = itemArranger->GetAdoptedSize(expectedViewSize);
					Size adoptedSize = Size(adoptedViewSize.x + x, adoptedViewSize.y + y);
					return adoptedSize;
				}
				return expectedSize;
			}
			
			bool GuiListControl::GetDisplayItemBackground()
			{
				return displayItemBackground;
			}

			void GuiListControl::SetDisplayItemBackground(bool value)
			{
				if (displayItemBackground != value)
				{
					displayItemBackground = value;
					SetStyleAndArranger(itemStyleProperty, itemArranger);
				}
			}

/***********************************************************************
GuiSelectableListControl
***********************************************************************/

			void GuiSelectableListControl::NotifySelectionChanged(bool triggeredByItemContentModified)
			{
				SelectionChanged.Execute(GetNotifyEventArguments());
			}

			void GuiSelectableListControl::OnItemModified(vint start, vint count, vint newCount, bool itemReferenceUpdated)
			{
				GuiListControl::OnItemModified(start, count, newCount, itemReferenceUpdated);
				if (count != newCount)
				{
					ClearSelection();
				}
				else if (itemReferenceUpdated)
				{
					if (selectedItems.Count() > 0)
					{
						vint cmin = start;
						vint cmax = start + count - 1;
						vint smin = selectedItems[0];
						vint smax = selectedItems[selectedItems.Count() - 1];
						if (cmin <= smax && smin <= cmax)
						{
							ClearSelection();
						}
					}
				}
				else
				{
					if (GetSelectedItemIndex() == start)
					{
						NotifySelectionChanged(true);
					}
				}
			}

			void GuiSelectableListControl::OnStyleInstalled(vint itemIndex, ItemStyle* style, bool refreshPropertiesOnly)
			{
				GuiListControl::OnStyleInstalled(itemIndex, style, refreshPropertiesOnly);
				style->SetSelected(selectedItems.Contains(itemIndex));
			}

			void GuiSelectableListControl::OnItemSelectionChanged(vint itemIndex, bool value)
			{
				if(auto style = itemArranger->GetVisibleStyle(itemIndex))
				{
					style->SetSelected(value);
				}
			}

			void GuiSelectableListControl::OnItemSelectionCleared()
			{
				for (auto style : visibleStyles.Keys())
				{
					style->SetSelected(false);
				}
			}

			void GuiSelectableListControl::OnItemLeftButtonDown(compositions::GuiGraphicsComposition* sender, compositions::GuiItemMouseEventArgs& arguments)
			{
				if(GetVisuallyEnabled())
				{
					SelectItemsByClick(arguments.itemIndex, arguments.ctrl, arguments.shift, true);
				}
			}

			void GuiSelectableListControl::OnItemRightButtonDown(compositions::GuiGraphicsComposition* sender, compositions::GuiItemMouseEventArgs& arguments)
			{
				if(GetVisuallyEnabled())
				{
					SelectItemsByClick(arguments.itemIndex, arguments.ctrl, arguments.shift, false);
				}
			}

			void GuiSelectableListControl::NormalizeSelectedItemIndexStartEnd()
			{
				if (selectedItemIndexStart < 0 || selectedItemIndexStart >= itemProvider->Count())
				{
					selectedItemIndexStart = 0;
				}
				if (selectedItemIndexEnd < 0 || selectedItemIndexEnd >= itemProvider->Count())
				{
					selectedItemIndexEnd = 0;
				}
			}

			void GuiSelectableListControl::SetMultipleItemsSelectedSilently(vint start, vint end, bool selected)
			{
				if(start>end)
				{
					vint temp=start;
					start=end;
					end=temp;
				}
				vint count=itemProvider->Count();
				if(start<0) start=0;
				if(end>=count) end=count-1;
				for(vint i=start;i<=end;i++)
				{
					if(selected)
					{
						if(!selectedItems.Contains(i))
						{
							selectedItems.Add(i);
						}
					}
					else
					{
						selectedItems.Remove(i);
					}
					OnItemSelectionChanged(i, selected);
				}
			}

			void GuiSelectableListControl::OnKeyDown(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
				if(GetVisuallyEnabled())
				{
					if(SelectItemsByKey(arguments.code, arguments.ctrl, arguments.shift))
					{
						arguments.handled=true;
					}
				}
			}

			vint GuiSelectableListControl::FindItemByVirtualKeyDirection(vint index, compositions::KeyDirection keyDirection)
			{
				return GetArranger()->FindItemByVirtualKeyDirection(selectedItemIndexEnd, keyDirection);
			}

			GuiSelectableListControl::GuiSelectableListControl(theme::ThemeName themeName, list::IItemProvider* _itemProvider)
				:GuiListControl(themeName, _itemProvider, true)
				, multiSelect(false)
				, selectedItemIndexStart(-1)
				, selectedItemIndexEnd(-1)
			{
				SelectionChanged.SetAssociatedComposition(boundsComposition);
				ItemLeftButtonDown.AttachMethod(this, &GuiSelectableListControl::OnItemLeftButtonDown);
				ItemRightButtonDown.AttachMethod(this, &GuiSelectableListControl::OnItemRightButtonDown);
				if (focusableComposition)
				{
					focusableComposition->GetEventReceiver()->keyDown.AttachMethod(this, &GuiSelectableListControl::OnKeyDown);
				}
			}

			GuiSelectableListControl::~GuiSelectableListControl()
			{
			}

			bool GuiSelectableListControl::GetMultiSelect()
			{
				return multiSelect;
			}

			void GuiSelectableListControl::SetMultiSelect(bool value)
			{
				if (multiSelect != value)
				{
					multiSelect = value;
					ClearSelection();
				}
			}

			const collections::SortedList<vint>& GuiSelectableListControl::GetSelectedItems()
			{
				return selectedItems;
			}

			vint GuiSelectableListControl::GetSelectedItemIndex()
			{
				return selectedItems.Count() == 1 ? selectedItems[0] : -1;
			}

			WString GuiSelectableListControl::GetSelectedItemText()
			{
				vint index = GetSelectedItemIndex();
				if (index != -1)
				{
					return itemProvider->GetTextValue(index);
				}
				return L"";
			}

			bool GuiSelectableListControl::GetSelected(vint itemIndex)
			{
				return selectedItems.Contains(itemIndex);
			}

			void GuiSelectableListControl::SetSelected(vint itemIndex, bool value)
			{
				if (0 <= itemIndex && itemIndex < itemProvider->Count())
				{
					if (value)
					{
						if (!selectedItems.Contains(itemIndex))
						{
							if (!multiSelect)
							{
								selectedItems.Clear();
								OnItemSelectionCleared();
							}
							selectedItems.Add(itemIndex);
							OnItemSelectionChanged(itemIndex, value);
							NotifySelectionChanged(false);
						}
					}
					else
					{
						if (selectedItems.Remove(itemIndex))
						{
							OnItemSelectionChanged(itemIndex, value);
							NotifySelectionChanged(false);
						}
					}
					selectedItemIndexStart = itemIndex;
					selectedItemIndexEnd = itemIndex;
				}
			}

			bool GuiSelectableListControl::SelectItemsByClick(vint itemIndex, bool ctrl, bool shift, bool leftButton)
			{
				NormalizeSelectedItemIndexStartEnd();
				if (0 <= itemIndex && itemIndex < itemProvider->Count())
				{
					if (!leftButton)
					{
						if (selectedItems.Contains(itemIndex))
						{
							return true;
						}
					}
					if (!multiSelect)
					{
						shift = false;
						ctrl = false;
					}

					if (shift)
					{
						if (!ctrl)
						{
							selectedItems.Clear();
							OnItemSelectionCleared();
						}
						selectedItemIndexEnd = itemIndex;
						SetMultipleItemsSelectedSilently(selectedItemIndexStart, selectedItemIndexEnd, true);
						NotifySelectionChanged(false);
					}
					else
					{
						if (ctrl)
						{
							vint index = selectedItems.IndexOf(itemIndex);
							if (index == -1)
							{
								selectedItems.Add(itemIndex);
							}
							else
							{
								selectedItems.RemoveAt(index);
							}
							OnItemSelectionChanged(itemIndex, index == -1);
							NotifySelectionChanged(false);
						}
						else
						{
							selectedItems.Clear();
							OnItemSelectionCleared();
							selectedItems.Add(itemIndex);
							OnItemSelectionChanged(itemIndex, true);
							NotifySelectionChanged(false);
						}
						selectedItemIndexStart = itemIndex;
						selectedItemIndexEnd = itemIndex;
					}
					return true;
				}
				return false;
			}

			bool GuiSelectableListControl::SelectItemsByKey(VKEY code, bool ctrl, bool shift)
			{
				if (!GetArranger()) return false;

				NormalizeSelectedItemIndexStartEnd();
				KeyDirection keyDirection = KeyDirection::Up;
				switch (code)
				{
				case VKEY::KEY_UP:
					keyDirection = KeyDirection::Up;
					break;
				case VKEY::KEY_DOWN:
					keyDirection = KeyDirection::Down;
					break;
				case VKEY::KEY_LEFT:
					keyDirection = KeyDirection::Left;
					break;
				case VKEY::KEY_RIGHT:
					keyDirection = KeyDirection::Right;
					break;
				case VKEY::KEY_HOME:
					keyDirection = KeyDirection::Home;
					break;
				case VKEY::KEY_END:
					keyDirection = KeyDirection::End;
					break;
				case VKEY::KEY_PRIOR:
					keyDirection = KeyDirection::PageUp;
					break;
				case VKEY::KEY_NEXT:
					keyDirection = KeyDirection::PageDown;
					break;
				default:
					return false;
				}

				if (GetAxis())
				{
					keyDirection = GetAxis()->RealKeyDirectionToVirtualKeyDirection(keyDirection);
				}
				vint itemIndex = FindItemByVirtualKeyDirection(selectedItemIndexEnd, keyDirection);
				if (SelectItemsByClick(itemIndex, ctrl, shift, true))
				{
					return EnsureItemVisible(itemIndex);
				}
				else
				{
					return false;
				}
			}

			void GuiSelectableListControl::ClearSelection()
			{
				if(selectedItems.Count()>0)
				{
					selectedItems.Clear();
					selectedItemIndexStart = -1;
					selectedItemIndexEnd = -1;
					OnItemSelectionCleared();
					NotifySelectionChanged(false);
				}
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\GUILISTVIEWCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace elements;
			using namespace compositions;
			using namespace collections;
			using namespace reflection::description;

/***********************************************************************
GuiListViewColumnHeader
***********************************************************************/

			void GuiListViewColumnHeader::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiListViewColumnHeader::AfterControlTemplateInstalled_(bool initialize)
			{
				TypedControlTemplateObject(true)->SetSortingState(columnSortingState);
			}
			
			GuiListViewColumnHeader::GuiListViewColumnHeader(theme::ThemeName themeName)
				:GuiMenuButton(themeName)
			{
			}

			GuiListViewColumnHeader::~GuiListViewColumnHeader()
			{
			}

			bool GuiListViewColumnHeader::IsAltAvailable()
			{
				return false;
			}

			ColumnSortingState GuiListViewColumnHeader::GetColumnSortingState()
			{
				return columnSortingState;
			}

			void GuiListViewColumnHeader::SetColumnSortingState(ColumnSortingState value)
			{
				if (columnSortingState != value)
				{
					columnSortingState = value;
					TypedControlTemplateObject(true)->SetSortingState(columnSortingState);
				}
			}

/***********************************************************************
GuiListViewBase
***********************************************************************/

			void GuiListViewBase::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiListViewBase::AfterControlTemplateInstalled_(bool initialize)
			{
			}

			GuiListViewBase::GuiListViewBase(theme::ThemeName themeName, list::IItemProvider* _itemProvider)
				:GuiSelectableListControl(themeName, _itemProvider)
			{
				ColumnClicked.SetAssociatedComposition(boundsComposition);
			}

			GuiListViewBase::~GuiListViewBase()
			{
			}

			namespace list
			{
				
/***********************************************************************
ListViewColumnItemArranger::ColumnItemViewCallback
***********************************************************************/

				ListViewColumnItemArranger::ColumnItemViewCallback::ColumnItemViewCallback(ListViewColumnItemArranger* _arranger)
					:arranger(_arranger)
				{
				}

				ListViewColumnItemArranger::ColumnItemViewCallback::~ColumnItemViewCallback()
				{
				}

				void ListViewColumnItemArranger::ColumnItemViewCallback::OnColumnRebuilt()
				{
					arranger->RebuildColumns();
				}

				void ListViewColumnItemArranger::ColumnItemViewCallback::OnColumnChanged(bool needToRefreshItems)
				{
					arranger->RefreshColumns();
				}
				
/***********************************************************************
ListViewColumnItemArranger::ColumnItemArrangerRepeatComposition
***********************************************************************/

				void ListViewColumnItemArranger::ColumnItemArrangerRepeatComposition::Layout_EndLayout(bool totalSizeUpdated)
				{
					TBase::ArrangerRepeatComposition::Layout_EndLayout(totalSizeUpdated);
					arranger->FixColumnsAfterLayout();
				}

				void ListViewColumnItemArranger::ColumnItemArrangerRepeatComposition::Layout_CalculateTotalSize(Size& full, Size& minimum)
				{
					TBase::ArrangerRepeatComposition::Layout_CalculateTotalSize(full, minimum);
					full.x += arranger->SplitterWidth;
					minimum.x += arranger->SplitterWidth;
				}

				ListViewColumnItemArranger::ColumnItemArrangerRepeatComposition::ColumnItemArrangerRepeatComposition(ListViewColumnItemArranger* _arranger)
					: TBase::ArrangerRepeatComposition(_arranger)
					, arranger(_arranger)
				{
				}
				
/***********************************************************************
ListViewColumnItemArranger
***********************************************************************/

				void ListViewColumnItemArranger::OnViewLocationChanged(compositions::GuiGraphicsComposition* composition, compositions::GuiEventArgs& arguments)
				{
					FixColumnsAfterViewLocationChanged();
				}

				void ListViewColumnItemArranger::ColumnClicked(vint index, compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					GuiItemEventArgs args(listView->ColumnClicked.GetAssociatedComposition());
					args.itemIndex=index;
					listView->ColumnClicked.Execute(args);
				}

				void ListViewColumnItemArranger::ColumnCachedBoundsChanged(vint index, compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
				{
					GuiBoundsComposition* buttonBounds=columnHeaderButtons[index]->GetBoundsComposition();
					vint size=buttonBounds->GetCachedBounds().Width();
					if(size>columnItemView->GetColumnSize(index))
					{
						columnItemView->SetColumnSize(index, size);
					}
				}

				void ListViewColumnItemArranger::ColumnHeaderSplitterLeftButtonDown(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
				{
					if(listView->GetVisuallyEnabled())
					{
						arguments.handled=true;
						splitterDragging=true;
						splitterLatestX=arguments.x;
					}
				}

				void ListViewColumnItemArranger::ColumnHeaderSplitterLeftButtonUp(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
				{
					if(listView->GetVisuallyEnabled())
					{
						arguments.handled=true;
						splitterDragging=false;
						splitterLatestX=0;
					}
				}

				void ListViewColumnItemArranger::ColumnHeaderSplitterMouseMove(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
				{
					if(splitterDragging)
					{
						vint offset=arguments.x-splitterLatestX;
						vint index=columnHeaderSplitters.IndexOf(dynamic_cast<GuiBoundsComposition*>(sender));
						if(index!=-1)
						{
							GuiBoundsComposition* buttonBounds=columnHeaderButtons[index]->GetBoundsComposition();
							Rect bounds=buttonBounds->GetCachedBounds();
							Rect newBounds(bounds.LeftTop(), Size(bounds.Width()+offset, bounds.Height()));
							buttonBounds->SetExpectedBounds(newBounds);

							vint finalSize=buttonBounds->GetCachedBounds().Width();
							columnItemView->SetColumnSize(index, finalSize);
						}
					}
				}

				void ListViewColumnItemArranger::ColumnHeadersCachedBoundsChanged(compositions::GuiGraphicsComposition* composition, compositions::GuiEventArgs& arguments)
				{
					UpdateRepeatConfig();
				}

				void ListViewColumnItemArranger::FixColumnsAfterViewLocationChanged()
				{
					vint x = GetRepeatComposition()->GetViewLocation().x;
					columnHeaders->SetExpectedBounds(Rect(Point(-x, 0), Size(0, 0)));
				}

				void ListViewColumnItemArranger::FixColumnsAfterLayout()
				{
					vint count = columnHeaders->GetParent()->Children().Count();
					columnHeaders->GetParent()->MoveChild(columnHeaders, count - 1);
					FixColumnsAfterViewLocationChanged();
				}

				vint ListViewColumnItemArranger::GetColumnsWidth()
				{
					vint width=columnHeaders->GetCachedBounds().Width()-SplitterWidth;
					if(width<SplitterWidth)
					{
						width=SplitterWidth;
					}
					return width;
				}

				vint ListViewColumnItemArranger::GetColumnsYOffset()
				{
					return columnHeaders->GetCachedBounds().Height();
				}

				void ListViewColumnItemArranger::DeleteColumnButtons()
				{
					// TODO: (enumerable) foreach:reversed
					for(vint i=columnHeaders->GetStackItems().Count()-1;i>=0;i--)
					{
						GuiStackItemComposition* item=columnHeaders->GetStackItems().Get(i);
						columnHeaders->RemoveChild(item);

						GuiControl* button=item->Children().Get(0)->GetAssociatedControl();
						if(button)
						{
							item->RemoveChild(button->GetBoundsComposition());
							delete button;
						}
						delete item;
					}
					columnHeaderButtons.Clear();
					columnHeaderSplitters.Clear();
				}

				void ListViewColumnItemArranger::RebuildColumns()
				{
					if (columnItemView && columnHeaderButtons.Count() == listViewItemView->GetColumnCount())
					{
						for (vint i = 0; i < listViewItemView->GetColumnCount(); i++)
						{
							GuiListViewColumnHeader* button = columnHeaderButtons[i];
							button->SetText(listViewItemView->GetColumnText(i));
							button->SetSubMenu(columnItemView->GetDropdownPopup(i), false);
							button->SetColumnSortingState(columnItemView->GetSortingState(i));
							button->GetBoundsComposition()->SetExpectedBounds(Rect(Point(0, 0), Size(columnItemView->GetColumnSize(i), 0)));
						}
					}
					else
					{
						DeleteColumnButtons();
						if (columnItemView && listViewItemView)
						{
							for (vint i = 0; i < listViewItemView->GetColumnCount(); i++)
							{
								GuiBoundsComposition* splitterComposition = new GuiBoundsComposition;
								splitterComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
								splitterComposition->SetAssociatedCursor(GetCurrentController()->ResourceService()->GetSystemCursor(INativeCursor::SizeWE));
								splitterComposition->SetAlignmentToParent(Margin(0, 0, -1, 0));
								splitterComposition->SetPreferredMinSize(Size(SplitterWidth, 0));
								columnHeaderSplitters.Add(splitterComposition);

								splitterComposition->GetEventReceiver()->leftButtonDown.AttachMethod(this, &ListViewColumnItemArranger::ColumnHeaderSplitterLeftButtonDown);
								splitterComposition->GetEventReceiver()->leftButtonUp.AttachMethod(this, &ListViewColumnItemArranger::ColumnHeaderSplitterLeftButtonUp);
								splitterComposition->GetEventReceiver()->mouseMove.AttachMethod(this, &ListViewColumnItemArranger::ColumnHeaderSplitterMouseMove);
							}
							for (vint i = 0; i < listViewItemView->GetColumnCount(); i++)
							{
								GuiListViewColumnHeader* button = new GuiListViewColumnHeader(theme::ThemeName::Unknown);
								button->SetAutoFocus(false);
								button->SetControlTemplate(listView->TypedControlTemplateObject(true)->GetColumnHeaderTemplate());
								button->Clicked.AttachLambda([this, i](GuiGraphicsComposition* sender, GuiEventArgs& args) { ColumnClicked(i, sender, args); });
								button->GetBoundsComposition()->CachedBoundsChanged.AttachLambda([this, i](GuiGraphicsComposition* sender, GuiEventArgs& args) { ColumnCachedBoundsChanged(i, sender, args); });
								columnHeaderButtons.Add(button);
								if (i > 0)
								{
									button->GetContainerComposition()->AddChild(columnHeaderSplitters[i - 1]);
								}

								GuiStackItemComposition* item = new GuiStackItemComposition;
								item->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
								item->AddChild(button->GetBoundsComposition());
								columnHeaders->AddChild(item);
							}
							if (listViewItemView->GetColumnCount() > 0)
							{
								GuiBoundsComposition* splitterComposition = columnHeaderSplitters[listViewItemView->GetColumnCount() - 1];

								GuiStackItemComposition* item = new GuiStackItemComposition;
								item->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
								item->AddChild(splitterComposition);
								columnHeaders->AddChild(item);
							}
						}
					}

					RefreshColumns();
					callback->OnTotalSizeChanged();
				}

				void ListViewColumnItemArranger::UpdateRepeatConfig()
				{
					GetRepeatComposition()->SetItemWidth(GetColumnsWidth());
					GetRepeatComposition()->SetItemYOffset(GetColumnsYOffset());
				}

				void ListViewColumnItemArranger::RefreshColumns()
				{
					if (columnItemView && listViewItemView)
					{
						for (vint i = 0; i < listViewItemView->GetColumnCount(); i++)
						{
							auto button = columnHeaderButtons[i];
							button->SetText(listViewItemView->GetColumnText(i));
							button->SetSubMenu(columnItemView->GetDropdownPopup(i), false);
							button->SetColumnSortingState(columnItemView->GetSortingState(i));
							button->GetBoundsComposition()->SetExpectedBounds(Rect(Point(0, 0), Size(columnItemView->GetColumnSize(i), 0)));
						}
						columnHeaders->ForceCalculateSizeImmediately();
						UpdateRepeatConfig();
					}
				}

				ListViewColumnItemArranger::ListViewColumnItemArranger()
					: TBase(new TBase::ArrangerRepeatComposition(this))
				{
					columnHeaders = new GuiStackComposition;
					columnHeaders->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					columnHeaders->CachedBoundsChanged.AttachMethod(this, &ListViewColumnItemArranger::ColumnHeadersCachedBoundsChanged);
					columnItemViewCallback = Ptr(new ColumnItemViewCallback(this));
					GetRepeatComposition()->ViewLocationChanged.AttachMethod(this, &ListViewColumnItemArranger::OnViewLocationChanged);
				}

				ListViewColumnItemArranger::~ListViewColumnItemArranger()
				{
					if(!columnHeaders->GetParent())
					{
						DeleteColumnButtons();
						delete columnHeaders;
					}
				}

				Size ListViewColumnItemArranger::GetTotalSize()
				{
					Size size = TBase::GetTotalSize();
					size.x += SplitterWidth;
					return size;
				}

				void ListViewColumnItemArranger::AttachListControl(GuiListControl* value)
				{
					TBase::AttachListControl(value);
					listView = dynamic_cast<GuiListViewBase*>(value);
					if (listView)
					{
						listViewItemView = dynamic_cast<IListViewItemView*>(listView->GetItemProvider()->RequestView(WString::Unmanaged(IListViewItemView::Identifier)));
						columnItemView = dynamic_cast<IColumnItemView*>(listView->GetItemProvider()->RequestView(WString::Unmanaged(IColumnItemView::Identifier)));
						listView->GetContainerComposition()->AddChild(columnHeaders);
						if (columnItemView)
						{
							columnItemView->AttachCallback(columnItemViewCallback.Obj());
							RebuildColumns();
						}
					}
				}

				void ListViewColumnItemArranger::DetachListControl()
				{
					if (listView)
					{
						if (columnItemView)
						{
							columnItemView->DetachCallback(columnItemViewCallback.Obj());
							columnItemView = nullptr;
						}
						listViewItemView = nullptr;
						listView->GetContainerComposition()->RemoveChild(columnHeaders);
						listView = nullptr;
					}
					TBase::DetachListControl();
				}

				const ListViewColumnItemArranger::ColumnHeaderButtonList& ListViewColumnItemArranger::GetColumnButtons()
				{
					return columnHeaderButtons;
				}

				const ListViewColumnItemArranger::ColumnHeaderSplitterList& ListViewColumnItemArranger::GetColumnSplitters()
				{
					return columnHeaderSplitters;
				}
			}

/***********************************************************************
GuiListView
***********************************************************************/

			void GuiVirtualListView::OnStyleInstalled(vint itemIndex, ItemStyle* style, bool refreshPropertiesOnly)
			{
				GuiListViewBase::OnStyleInstalled(itemIndex, style, refreshPropertiesOnly);
				if (auto textItemStyle = dynamic_cast<templates::GuiTextListItemTemplate*>(style))
				{
					textItemStyle->SetTextColor(TypedControlTemplateObject(true)->GetPrimaryTextColor());
				}
				if (refreshPropertiesOnly)
				{
					if (auto predefinedItemStyle = dynamic_cast<list::DefaultListViewItemTemplate*>(style))
					{
						predefinedItemStyle->RefreshItem();
					}
				}
			}

			void GuiVirtualListView::OnItemTemplateChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				view = ListViewView::Unknown;
			}

			GuiVirtualListView::GuiVirtualListView(theme::ThemeName themeName, list::IItemProvider* _itemProvider)
				:GuiListViewBase(themeName, _itemProvider)
			{
				SetView(ListViewView::Detail);
			}

			GuiVirtualListView::~GuiVirtualListView()
			{
			}

			ListViewView GuiVirtualListView::GetView()
			{
				return view;
			}

			void GuiVirtualListView::SetView(ListViewView _view)
			{
				switch (_view)
				{
				case ListViewView::BigIcon:
					SetStyleAndArranger(
						[](const Value&) { return new list::BigIconListViewItemTemplate; },
						Ptr(new list::FixedSizeMultiColumnItemArranger)
						);
					break;
				case ListViewView::SmallIcon:
					SetStyleAndArranger(
						[](const Value&) { return new list::SmallIconListViewItemTemplate; },
						Ptr(new list::FixedSizeMultiColumnItemArranger)
						);
					break;
				case ListViewView::List:
					SetStyleAndArranger(
						[](const Value&) { return new list::ListListViewItemTemplate; },
						Ptr(new list::FixedHeightMultiColumnItemArranger)
						);
					break;
				case ListViewView::Tile:
					SetStyleAndArranger(
						[](const Value&) { return new list::TileListViewItemTemplate; },
						Ptr(new list::FixedSizeMultiColumnItemArranger)
						);
					break;
				case ListViewView::Information:
					SetStyleAndArranger(
						[](const Value&) { return new list::InformationListViewItemTemplate; },
						Ptr(new list::FixedHeightItemArranger)
						);
					break;
				case ListViewView::Detail:
					SetStyleAndArranger(
						[](const Value&) { return new list::DetailListViewItemTemplate; },
						Ptr(new list::ListViewColumnItemArranger)
						);
					break;
				default:;
				}
				view = _view;
			}

/***********************************************************************
GuiListView
***********************************************************************/

			GuiListView::GuiListView(theme::ThemeName themeName)
				:GuiVirtualListView(themeName, new list::ListViewItemProvider)
			{
				items=dynamic_cast<list::ListViewItemProvider*>(itemProvider.Obj());
			}

			GuiListView::~GuiListView()
			{
			}

			list::ListViewItemProvider& GuiListView::GetItems()
			{
				return *items;
			}

			list::ListViewDataColumns& GuiListView::GetDataColumns()
			{
				return items->GetDataColumns();
			}

			list::ListViewColumns& GuiListView::GetColumns()
			{
				return items->GetColumns();
			}

			Ptr<list::ListViewItem> GuiListView::GetSelectedItem()
			{
				vint index = GetSelectedItemIndex();
				if (index == -1) return 0;
				return items->Get(index);
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\GUITEXTLISTCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace collections;
			using namespace elements;
			using namespace compositions;
			using namespace reflection::description;

/***********************************************************************
GuiVirtualTextList
***********************************************************************/

			void GuiVirtualTextList::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiVirtualTextList::AfterControlTemplateInstalled_(bool initialize)
			{
			}

			void GuiVirtualTextList::OnStyleInstalled(vint itemIndex, ItemStyle* style, bool refreshPropertiesOnly)
			{
				GuiSelectableListControl::OnStyleInstalled(itemIndex, style, refreshPropertiesOnly);
				if (auto textItemStyle = dynamic_cast<templates::GuiTextListItemTemplate*>(style))
				{
					textItemStyle->SetTextColor(TypedControlTemplateObject(true)->GetTextColor());
					if (auto textItemView = dynamic_cast<list::ITextItemView*>(itemProvider->RequestView(WString::Unmanaged(list::ITextItemView::Identifier))))
					{
						textItemStyle->SetChecked(textItemView->GetChecked(itemIndex));
					}
				}
				if (refreshPropertiesOnly)
				{
					if (auto predefinedItemStyle = dynamic_cast<list::DefaultTextListItemTemplate*>(style))
					{
						predefinedItemStyle->RefreshItem();
					}
				}
			}

			void GuiVirtualTextList::OnItemTemplateChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				view = TextListView::Unknown;
			}

			GuiVirtualTextList::GuiVirtualTextList(theme::ThemeName themeName, list::IItemProvider* _itemProvider)
				:GuiSelectableListControl(themeName, _itemProvider)
			{
				ItemTemplateChanged.AttachMethod(this, &GuiVirtualTextList::OnItemTemplateChanged);
				ItemChecked.SetAssociatedComposition(boundsComposition);

				if (focusableComposition)
				{
					focusableComposition->GetEventReceiver()->keyDown.AttachMethod(this, &GuiVirtualTextList::OnKeyDown);
				}

				SetView(TextListView::Text);
			}

			GuiVirtualTextList::~GuiVirtualTextList()
			{
			}

			TextListView GuiVirtualTextList::GetView()
			{
				return view;
			}

			void GuiVirtualTextList::SetView(TextListView _view)
			{
				switch (_view)
				{
				case TextListView::Text:
					SetStyleAndArranger(
						[](const Value&) { return new list::DefaultTextListItemTemplate; },
						Ptr(new list::FixedHeightItemArranger)
					);
					break;
				case TextListView::Check:
					SetStyleAndArranger(
						[](const Value&) { return new list::DefaultCheckTextListItemTemplate; },
						Ptr(new list::FixedHeightItemArranger)
					);
					break;
				case TextListView::Radio:
					SetStyleAndArranger(
						[](const Value&) { return new list::DefaultRadioTextListItemTemplate; },
						Ptr(new list::FixedHeightItemArranger)
					);
					break;
				default:;
				}
				view = _view;
			}

			void GuiVirtualTextList::OnKeyDown(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::GuiVirtualTextList::OnKeyDown(GuiGraphicsComposition*, GuiKeyEventArgs&)#"
				if (arguments.code == VKEY::KEY_SPACE && !arguments.ctrl && !arguments.shift && !arguments.alt)
				{
					const auto& selectedItems = GetSelectedItems();
					if (selectedItems.Count() > 0)
					{
						if (auto textItemView = dynamic_cast<list::ITextItemView*>(itemProvider->RequestView(WString::Unmanaged(list::ITextItemView::Identifier))))
						{
							bool hasUnchecked = false;
							for (vint i = 0; i < selectedItems.Count(); i++)
							{
								if (!textItemView->GetChecked(selectedItems[i]))
								{
									hasUnchecked = true;
									break;
								}
							}
							
							itemProvider->PushEditing();
							for (vint i = 0; i < selectedItems.Count(); i++)
							{
								vint itemIndex = selectedItems[i];
								if (textItemView->GetChecked(itemIndex) != hasUnchecked)
								{
									textItemView->SetChecked(itemIndex, hasUnchecked);
							
									GuiItemEventArgs eventArgs;
									eventArgs.itemIndex = itemIndex;
									ItemChecked.Execute(eventArgs);
								}
							}
							CHECK_ERROR(itemProvider->PopEditing(), ERROR_MESSAGE_PREFIX L"PushEditing and PopEditing calls are not paired.");
							
							arguments.handled = true;
						}
					}
				}
#undef ERROR_MESSAGE_PREFIX
			}

/***********************************************************************
GuiTextList
***********************************************************************/

			void GuiTextList::OnItemCheckedChanged(vint itemIndex)
			{
				GuiItemEventArgs eventArgs;
				eventArgs.itemIndex = itemIndex;
				ItemChecked.Execute(eventArgs);
			}

			GuiTextList::GuiTextList(theme::ThemeName themeName)
				:GuiVirtualTextList(themeName, new list::TextItemProvider(this))
			{
				items=dynamic_cast<list::TextItemProvider*>(itemProvider.Obj());
			}

			GuiTextList::~GuiTextList()
			{
			}

			list::TextItemProvider& GuiTextList::GetItems()
			{
				return *items;
			}

			Ptr<list::TextItem> GuiTextList::GetSelectedItem()
			{
				vint index = GetSelectedItemIndex();
				if (index == -1) return 0;
				return items->Get(index);
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\GUITREEVIEWCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace elements;
			using namespace compositions;
			using namespace reflection::description;

/***********************************************************************
GuiVirtualTreeListControl
***********************************************************************/

			void GuiVirtualTreeListControl::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiVirtualTreeListControl::AfterControlTemplateInstalled_(bool initialize)
			{
			}

			void GuiVirtualTreeListControl::OnAttached(tree::INodeRootProvider* provider)
			{
			}

			void GuiVirtualTreeListControl::OnBeforeItemModified(tree::INodeProvider* parentNode, vint start, vint count, vint newCount, bool itemReferenceUpdated)
			{
			}

			void GuiVirtualTreeListControl::OnAfterItemModified(tree::INodeProvider* parentNode, vint start, vint count, vint newCount, bool itemReferenceUpdated)
			{
			}

			void GuiVirtualTreeListControl::OnItemExpanded(tree::INodeProvider* node)
			{
				GuiNodeEventArgs arguments;
				(GuiEventArgs&)arguments=GetNotifyEventArguments();
				arguments.node=node;
				NodeExpanded.Execute(arguments);
			}

			void GuiVirtualTreeListControl::OnItemCollapsed(tree::INodeProvider* node)
			{
				GuiNodeEventArgs arguments;
				(GuiEventArgs&)arguments=GetNotifyEventArguments();
				arguments.node=node;
				NodeCollapsed.Execute(arguments);
			}

			vint GuiVirtualTreeListControl::FindItemByVirtualKeyDirection(vint index, compositions::KeyDirection keyDirection)
			{
				vint newIndex = GuiSelectableListControl::FindItemByVirtualKeyDirection(index, keyDirection);
				if (newIndex != -1) return newIndex;

				auto selectedNode = nodeItemView->RequestNode(index);
				if (selectedNode)
				{
					bool hasChildren = selectedNode->GetChildCount() > 0;
					bool expanding = selectedNode->GetExpanding();
					switch (keyDirection)
					{
					case KeyDirection::Right:
						if (hasChildren)
						{
							if (expanding)
							{
								selectedNode = selectedNode->GetChild(0);
							}
							else
							{
								selectedNode->SetExpanding(true);
							}
						}
						break;
					case KeyDirection::Left:
						{
							selectedNode->SetExpanding(false);
							if (!expanding || !hasChildren)
							{
								selectedNode = selectedNode->GetParent();
							}
						}
						break;
					default:;
					}
				}

				return selectedNode ? nodeItemView->CalculateNodeVisibilityIndex(selectedNode.Obj()) : -1;
			}

			void GuiVirtualTreeListControl::OnItemMouseEvent(compositions::GuiNodeMouseEvent& nodeEvent, compositions::GuiGraphicsComposition* sender, compositions::GuiItemMouseEventArgs& arguments)
			{
				auto node = GetNodeItemView()->RequestNode(arguments.itemIndex);
				if (node)
				{
					GuiNodeMouseEventArgs redirectArguments;
					(GuiMouseEventArgs&)redirectArguments = arguments;
					redirectArguments.node = node.Obj();
					nodeEvent.Execute(redirectArguments);
					(GuiMouseEventArgs&)arguments = redirectArguments;
				}
			}

			void GuiVirtualTreeListControl::OnItemNotifyEvent(compositions::GuiNodeNotifyEvent& nodeEvent, compositions::GuiGraphicsComposition* sender, compositions::GuiItemEventArgs& arguments)
			{
				if (auto node = GetNodeItemView()->RequestNode(arguments.itemIndex))
				{
					GuiNodeEventArgs redirectArguments;
					(GuiEventArgs&)redirectArguments = arguments;
					redirectArguments.node = node.Obj();
					nodeEvent.Execute(redirectArguments);
					(GuiEventArgs&)arguments = redirectArguments;
				}
			}

#define ATTACH_ITEM_MOUSE_EVENT(NODEEVENTNAME, ITEMEVENTNAME)\
					{\
						ITEMEVENTNAME.AttachFunction([this](GuiGraphicsComposition* sender, GuiItemMouseEventArgs& args){ OnItemMouseEvent(NODEEVENTNAME, sender, args); });\
					}\

#define ATTACH_ITEM_NOTIFY_EVENT(NODEEVENTNAME, ITEMEVENTNAME)\
					{\
						ITEMEVENTNAME.AttachFunction([this](GuiGraphicsComposition* sender, GuiItemEventArgs& args){ OnItemNotifyEvent(NODEEVENTNAME, sender, args); });\
					}\

			void GuiVirtualTreeListControl::OnNodeLeftButtonDoubleClick(compositions::GuiGraphicsComposition* sender, compositions::GuiNodeMouseEventArgs& arguments)
			{
				if (arguments.node->GetChildCount() > 0)
				{
					arguments.node->SetExpanding(!arguments.node->GetExpanding());
				}
			}

			GuiVirtualTreeListControl::GuiVirtualTreeListControl(theme::ThemeName themeName, Ptr<tree::INodeRootProvider> _nodeRootProvider)
				:GuiSelectableListControl(themeName, new tree::NodeItemProvider(_nodeRootProvider))
			{
				nodeItemProvider = dynamic_cast<tree::NodeItemProvider*>(GetItemProvider());
				nodeItemView = dynamic_cast<tree::INodeItemView*>(GetItemProvider()->RequestView(WString::Unmanaged(tree::INodeItemView::Identifier)));

				NodeLeftButtonDown.SetAssociatedComposition(boundsComposition);
				NodeLeftButtonUp.SetAssociatedComposition(boundsComposition);
				NodeLeftButtonDoubleClick.SetAssociatedComposition(boundsComposition);
				NodeMiddleButtonDown.SetAssociatedComposition(boundsComposition);
				NodeMiddleButtonUp.SetAssociatedComposition(boundsComposition);
				NodeMiddleButtonDoubleClick.SetAssociatedComposition(boundsComposition);
				NodeRightButtonDown.SetAssociatedComposition(boundsComposition);
				NodeRightButtonUp.SetAssociatedComposition(boundsComposition);
				NodeRightButtonDoubleClick.SetAssociatedComposition(boundsComposition);
				NodeMouseMove.SetAssociatedComposition(boundsComposition);
				NodeMouseEnter.SetAssociatedComposition(boundsComposition);
				NodeMouseLeave.SetAssociatedComposition(boundsComposition);
				NodeExpanded.SetAssociatedComposition(boundsComposition);
				NodeCollapsed.SetAssociatedComposition(boundsComposition);

				ATTACH_ITEM_MOUSE_EVENT(NodeLeftButtonDown, ItemLeftButtonDown);
				ATTACH_ITEM_MOUSE_EVENT(NodeLeftButtonUp, ItemLeftButtonUp);
				ATTACH_ITEM_MOUSE_EVENT(NodeLeftButtonDoubleClick, ItemLeftButtonDoubleClick);
				ATTACH_ITEM_MOUSE_EVENT(NodeMiddleButtonDown, ItemMiddleButtonDown);
				ATTACH_ITEM_MOUSE_EVENT(NodeMiddleButtonUp, ItemMiddleButtonUp);
				ATTACH_ITEM_MOUSE_EVENT(NodeMiddleButtonDoubleClick, ItemMiddleButtonDoubleClick);
				ATTACH_ITEM_MOUSE_EVENT(NodeRightButtonDown, ItemRightButtonDown);
				ATTACH_ITEM_MOUSE_EVENT(NodeRightButtonUp, ItemRightButtonUp);
				ATTACH_ITEM_MOUSE_EVENT(NodeRightButtonDoubleClick, ItemRightButtonDoubleClick);
				ATTACH_ITEM_MOUSE_EVENT(NodeMouseMove, ItemMouseMove);
				ATTACH_ITEM_NOTIFY_EVENT(NodeMouseEnter, ItemMouseEnter);
				ATTACH_ITEM_NOTIFY_EVENT(NodeMouseLeave, ItemMouseLeave);

				nodeItemProvider->GetRoot()->AttachCallback(this);
				NodeLeftButtonDoubleClick.AttachMethod(this, &GuiVirtualTreeListControl::OnNodeLeftButtonDoubleClick);
			}

#undef ATTACH_ITEM_MOUSE_EVENT
#undef ATTACH_ITEM_NOTIFY_EVENT

			GuiVirtualTreeListControl::~GuiVirtualTreeListControl()
			{
			}

			tree::INodeItemView* GuiVirtualTreeListControl::GetNodeItemView()
			{
				return nodeItemView;
			}

			tree::INodeRootProvider* GuiVirtualTreeListControl::GetNodeRootProvider()
			{
				return nodeItemProvider->GetRoot().Obj();
			}

/***********************************************************************
GuiVirtualTreeView
***********************************************************************/

			templates::GuiTreeItemTemplate* GuiVirtualTreeView::GetStyleFromNode(tree::INodeProvider* node)
			{
				if (itemArranger)
				{
					vint index = nodeItemView->CalculateNodeVisibilityIndex(node);
					if (index != -1)
					{
						auto style = itemArranger->GetVisibleStyle(index);
						return dynamic_cast<templates::GuiTreeItemTemplate*>(style);
					}
				}
				return nullptr;
			}

			void GuiVirtualTreeView::SetStyleExpanding(tree::INodeProvider* node, bool expanding)
			{
				if (auto treeItemStyle = GetStyleFromNode(node))
				{
					treeItemStyle->SetExpanding(expanding);
				}
			}

			void GuiVirtualTreeView::SetStyleExpandable(tree::INodeProvider* node, bool expandable)
			{
				if (auto treeItemStyle = GetStyleFromNode(node))
				{
					treeItemStyle->SetExpandable(expandable);
				}
			}

			void GuiVirtualTreeView::OnAfterItemModified(tree::INodeProvider* parentNode, vint start, vint count, vint newCount, bool itemReferenceUpdated)
			{
				GuiVirtualTreeListControl::OnAfterItemModified(parentNode, start, count, newCount, itemReferenceUpdated);
				SetStyleExpandable(parentNode, parentNode->GetChildCount() > 0);
			}

			void GuiVirtualTreeView::OnItemExpanded(tree::INodeProvider* node)
			{
				GuiVirtualTreeListControl::OnItemExpanded(node);
				SetStyleExpanding(node, true);
			}

			void GuiVirtualTreeView::OnItemCollapsed(tree::INodeProvider* node)
			{
				GuiVirtualTreeListControl::OnItemCollapsed(node);
				SetStyleExpanding(node, false);
			}
			
			void GuiVirtualTreeView::OnStyleInstalled(vint itemIndex, ItemStyle* style, bool refreshPropertiesOnly)
			{
				GuiVirtualTreeListControl::OnStyleInstalled(itemIndex, style, refreshPropertiesOnly);
				if (auto textItemStyle = dynamic_cast<templates::GuiTextListItemTemplate*>(style))
				{
					textItemStyle->SetTextColor(TypedControlTemplateObject(true)->GetTextColor());
				}
				if (auto treeItemStyle = dynamic_cast<templates::GuiTreeItemTemplate*>(style))
				{
					treeItemStyle->SetTextColor(TypedControlTemplateObject(true)->GetTextColor());

					if (treeViewItemView)
					{
						if (auto node = nodeItemView->RequestNode(itemIndex))
						{
							treeItemStyle->SetImage(treeViewItemView->GetNodeImage(node.Obj()));
							treeItemStyle->SetExpanding(node->GetExpanding());
							treeItemStyle->SetExpandable(node->GetChildCount() > 0);
							{
								vint level = -1;
								auto current = node;
								while (current->GetParent())
								{
									level++;
									current = current->GetParent();
								}
								treeItemStyle->SetLevel(level);
							}
						}
					}
				}
				if (refreshPropertiesOnly)
				{
					if (auto predefinedItemStyle = dynamic_cast<tree::DefaultTreeItemTemplate*>(style))
					{
						predefinedItemStyle->RefreshItem();
					}
				}
			}

			GuiVirtualTreeView::GuiVirtualTreeView(theme::ThemeName themeName, Ptr<tree::INodeRootProvider> _nodeRootProvider)
				:GuiVirtualTreeListControl(themeName, _nodeRootProvider)
			{
				treeViewItemView = dynamic_cast<tree::ITreeViewItemView*>(GetNodeRootProvider()->RequestView(WString::Unmanaged(tree::ITreeViewItemView::Identifier)));
				SetStyleAndArranger(
					[](const Value&) { return new tree::DefaultTreeItemTemplate; },
					Ptr(new list::FixedHeightItemArranger)
				);
			}

			GuiVirtualTreeView::~GuiVirtualTreeView()
			{
			}

/***********************************************************************
GuiTreeView
***********************************************************************/

			GuiTreeView::GuiTreeView(theme::ThemeName themeName)
				:GuiVirtualTreeView(themeName, Ptr(new tree::TreeViewItemRootProvider))
			{
				nodes = nodeItemProvider->GetRoot().Cast<tree::TreeViewItemRootProvider>();
			}

			GuiTreeView::~GuiTreeView()
			{
			}

			Ptr<tree::TreeViewItemRootProvider> GuiTreeView::Nodes()
			{
				return nodes;
			}

			Ptr<tree::TreeViewItem> GuiTreeView::GetSelectedItem()
			{
				Ptr<tree::TreeViewItem> result;
				vint index = GetSelectedItemIndex();
				if (index != -1)
				{
					if (auto node = nodeItemView->RequestNode(index))
					{
						if (auto memoryNode = node.Cast<tree::MemoryNodeProvider>())
						{
							result = memoryNode->GetData().Cast<tree::TreeViewItem>();
						}
					}
				}
				return result;
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\ITEMPROVIDER_BINDING.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace collections;
			using namespace list;
			using namespace tree;
			using namespace reflection::description;

/***********************************************************************
TextItemBindableProvider
***********************************************************************/

			TextItemBindableProvider::TextItemBindableProvider()
			{
			}

			TextItemBindableProvider::~TextItemBindableProvider()
			{
				if (itemChangedEventHandler)
				{
					auto ol = itemSource.Cast<IValueObservableList>();
					ol->ItemChanged.Remove(itemChangedEventHandler);
				}
			}

			Ptr<description::IValueEnumerable> TextItemBindableProvider::GetItemSource()
			{
				return itemSource;
			}

			void TextItemBindableProvider::SetItemSource(Ptr<description::IValueEnumerable> _itemSource)
			{
				vint oldCount = 0;
				if (itemSource)
				{
					oldCount = itemSource->GetCount();
				}
				if (itemChangedEventHandler)
				{
					auto ol = itemSource.Cast<IValueObservableList>();
					ol->ItemChanged.Remove(itemChangedEventHandler);
				}

				itemSource = nullptr;
				itemChangedEventHandler = nullptr;

				if (_itemSource)
				{
					if (auto ol = _itemSource.Cast<IValueObservableList>())
					{
						itemSource = ol;
						itemChangedEventHandler = ol->ItemChanged.Add([this](vint start, vint oldCount, vint newCount)
						{
							InvokeOnItemModified(start, oldCount, newCount, true);
						});
					}
					else if (auto rl = _itemSource.Cast<IValueReadonlyList>())
					{
						itemSource = rl;
					}
					else
					{
						itemSource = IValueList::Create(GetLazyList<Value>(_itemSource));
					}
				}

				InvokeOnItemModified(0, oldCount, itemSource ? itemSource->GetCount() : 0, true);
			}

			description::Value TextItemBindableProvider::Get(vint index)
			{
				if (!itemSource) return Value();
				return itemSource->Get(index);
			}

			void TextItemBindableProvider::UpdateBindingProperties()
			{
				InvokeOnItemModified(0, Count(), Count(), false);
			}

			bool TextItemBindableProvider::NotifyUpdate(vint start, vint count, bool itemReferenceUpdated)
			{
				if (!itemSource) return false;
				if (start<0 || start >= itemSource->GetCount() || count <= 0 || start + count > itemSource->GetCount())
				{
					return false;
				}
				else
				{
					InvokeOnItemModified(start, count, count, itemReferenceUpdated);
					return true;
				}
			}

			// ===================== GuiListControl::IItemProvider =====================
			
			vint TextItemBindableProvider::Count()
			{
				if (!itemSource) return 0;
				return itemSource->GetCount();
			}

			WString TextItemBindableProvider::GetTextValue(vint itemIndex)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::TextItemBindableProvider::GetTextValue(vint)#"
				CHECK_ERROR(itemSource, ERROR_MESSAGE_PREFIX L"ItemSource is not set.");
				CHECK_ERROR(0 <= itemIndex && itemIndex < itemSource->GetCount(), ERROR_MESSAGE_PREFIX L"Index out of range.");
				return ReadProperty(itemSource->Get(itemIndex), textProperty);
#undef ERROR_MESSAGE_PREFIX
			}
			
			IDescriptable* TextItemBindableProvider::RequestView(const WString& identifier)
			{
				if (identifier == ITextItemView::Identifier)
				{
					return (ITextItemView*)this;
				}
				else
				{
					return 0;
				}
			}
					
			// ===================== GuiListControl::IItemBindingView =====================

			description::Value TextItemBindableProvider::GetBindingValue(vint itemIndex)
			{
				return itemSource->Get(itemIndex);
			}
					
			// ===================== list::TextItemStyleProvider::ITextItemView =====================
			
			bool TextItemBindableProvider::GetChecked(vint itemIndex)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::TextItemBindableProvider::GetChecked(vint)#"
				CHECK_ERROR(itemSource, ERROR_MESSAGE_PREFIX L"ItemSource is not set.");
				CHECK_ERROR(0 <= itemIndex && itemIndex < itemSource->GetCount(), ERROR_MESSAGE_PREFIX L"Index out of range.");
				return ReadProperty(itemSource->Get(itemIndex), checkedProperty);
#undef ERROR_MESSAGE_PREFIX
			}
			
			void TextItemBindableProvider::SetChecked(vint itemIndex, bool value)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::TextItemBindableProvider::SetChecked(vint, bool)#"
				CHECK_ERROR(itemSource, ERROR_MESSAGE_PREFIX L"ItemSource is not set.");
				CHECK_ERROR(0 <= itemIndex && itemIndex < itemSource->GetCount(), ERROR_MESSAGE_PREFIX L"Index out of range.");
				auto thisValue = itemSource->Get(itemIndex);
				WriteProperty(thisValue, checkedProperty, value);
				InvokeOnItemModified(itemIndex, 1, 1, false);
#undef ERROR_MESSAGE_PREFIX
			}

/***********************************************************************
ListViewItemBindableProvider
***********************************************************************/

			ListViewItemBindableProvider::ListViewItemBindableProvider()
				:columns(this)
				, dataColumns(this)
			{
			}

			ListViewItemBindableProvider::~ListViewItemBindableProvider()
			{
				if (itemChangedEventHandler)
				{
					auto ol = itemSource.Cast<IValueObservableList>();
					ol->ItemChanged.Remove(itemChangedEventHandler);
				}
			}

			Ptr<description::IValueEnumerable> ListViewItemBindableProvider::GetItemSource()
			{
				return itemSource;
			}

			void ListViewItemBindableProvider::SetItemSource(Ptr<description::IValueEnumerable> _itemSource)
			{
				vint oldCount = 0;
				if (itemSource)
				{
					oldCount = itemSource->GetCount();
				}
				if (itemChangedEventHandler)
				{
					auto ol = itemSource.Cast<IValueObservableList>();
					ol->ItemChanged.Remove(itemChangedEventHandler);
				}

				itemSource = nullptr;
				itemChangedEventHandler = nullptr;

				if (_itemSource)
				{
					if (auto ol = _itemSource.Cast<IValueObservableList>())
					{
						itemSource = ol;
						itemChangedEventHandler = ol->ItemChanged.Add([this](vint start, vint oldCount, vint newCount)
						{
							InvokeOnItemModified(start, oldCount, newCount, true);
						});
					}
					else if (auto rl = _itemSource.Cast<IValueReadonlyList>())
					{
						itemSource = rl;
					}
					else
					{
						itemSource = IValueList::Create(GetLazyList<Value>(_itemSource));
					}
				}

				InvokeOnItemModified(0, oldCount, itemSource ? itemSource->GetCount() : 0, true);
			}

			description::Value ListViewItemBindableProvider::Get(vint index)
			{
				if (!itemSource) return Value();
				return itemSource->Get(index);
			}

			void ListViewItemBindableProvider::UpdateBindingProperties()
			{
				InvokeOnItemModified(0, Count(), Count(), false);
			}

			bool ListViewItemBindableProvider::NotifyUpdate(vint start, vint count, bool itemReferenceUpdated)
			{
				if (!itemSource) return false;
				if (start<0 || start >= itemSource->GetCount() || count <= 0 || start + count > itemSource->GetCount())
				{
					return false;
				}
				else
				{
					InvokeOnItemModified(start, count, count, itemReferenceUpdated);
					return true;
				}
			}

			list::ListViewDataColumns& ListViewItemBindableProvider::GetDataColumns()
			{
				return dataColumns;
			}

			list::ListViewColumns& ListViewItemBindableProvider::GetColumns()
			{
				return columns;
			}
					
			// ===================== list::IListViewItemProvider =====================

			void ListViewItemBindableProvider::RebuildAllItems()
			{
				InvokeOnItemModified(0, Count(), Count(), true);
			}

			void ListViewItemBindableProvider::RefreshAllItems()
			{
				InvokeOnItemModified(0, Count(), Count(), false);
			}

			void ListViewItemBindableProvider::NotifyColumnRebuilt()
			{
				for (auto callback : columnItemViewCallbacks)
				{
					callback->OnColumnRebuilt();
				}
				RebuildAllItems();
			}

			void ListViewItemBindableProvider::NotifyColumnChanged()
			{
				for (auto callback : columnItemViewCallbacks)
				{
					callback->OnColumnChanged(true);
				}
				RefreshAllItems();
			}

			// ===================== GuiListControl::IItemProvider =====================

			vint ListViewItemBindableProvider::Count()
			{
				if (!itemSource) return 0;
				return itemSource->GetCount();
			}

			WString ListViewItemBindableProvider::GetTextValue(vint itemIndex)
			{
				return GetText(itemIndex);
			}

			description::Value ListViewItemBindableProvider::GetBindingValue(vint itemIndex)
			{
				if (itemSource)
				{
					if (0 <= itemIndex && itemIndex < itemSource->GetCount())
					{
						return itemSource->Get(itemIndex);
					}
				}
				return Value();
			}

			IDescriptable* ListViewItemBindableProvider::RequestView(const WString& identifier)
			{
				if (identifier == IListViewItemView::Identifier)
				{
					return (IListViewItemView*)this;
				}
				else if (identifier == IColumnItemView::Identifier)
				{
					return (IColumnItemView*)this;
				}
				else
				{
					return 0;
				}
			}

			// ===================== list::ListViewItemStyleProvider::IListViewItemView =====================

			Ptr<GuiImageData> ListViewItemBindableProvider::GetSmallImage(vint itemIndex)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::ListViewItemBindableProvider::GetSmallImage(vint)#"
				CHECK_ERROR(itemSource, ERROR_MESSAGE_PREFIX L"ItemSource is not set.");
				CHECK_ERROR(0 <= itemIndex && itemIndex < itemSource->GetCount(), ERROR_MESSAGE_PREFIX L"Index out of range.");
				return ReadProperty(itemSource->Get(itemIndex), smallImageProperty);
#undef ERROR_MESSAGE_PREFIX
			}

			Ptr<GuiImageData> ListViewItemBindableProvider::GetLargeImage(vint itemIndex)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::ListViewItemBindableProvider::GetLargeImage(vint)#"
				CHECK_ERROR(itemSource, ERROR_MESSAGE_PREFIX L"ItemSource is not set.");
				CHECK_ERROR(0 <= itemIndex && itemIndex < itemSource->GetCount(), ERROR_MESSAGE_PREFIX L"Index out of range.");
				return ReadProperty(itemSource->Get(itemIndex), largeImageProperty);
#undef ERROR_MESSAGE_PREFIX
			}

			WString ListViewItemBindableProvider::GetText(vint itemIndex)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::ListViewItemBindableProvider::GetText(vint)#"
				CHECK_ERROR(itemSource, ERROR_MESSAGE_PREFIX L"ItemSource is not set.");
				CHECK_ERROR(0 <= itemIndex && itemIndex < itemSource->GetCount(), ERROR_MESSAGE_PREFIX L"Index out of range.");
				return ReadProperty(itemSource->Get(itemIndex), columns[0]->GetTextProperty());
#undef ERROR_MESSAGE_PREFIX
			}

			WString ListViewItemBindableProvider::GetSubItem(vint itemIndex, vint index)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::ListViewItemBindableProvider::GetSubItem(vint, vint)#"
				CHECK_ERROR(itemSource, ERROR_MESSAGE_PREFIX L"ItemSource is not set.");
				CHECK_ERROR(0 <= itemIndex && itemIndex < itemSource->GetCount(), ERROR_MESSAGE_PREFIX L"Index out of range.");
				CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"column index cannot be -1, use GetText(itemIndex) instead.");
				return ReadProperty(itemSource->Get(itemIndex), columns[index + 1]->GetTextProperty());
#undef ERROR_MESSAGE_PREFIX
			}

			vint ListViewItemBindableProvider::GetDataColumnCount()
			{
				return dataColumns.Count();
			}

			vint ListViewItemBindableProvider::GetDataColumn(vint index)
			{
				return dataColumns[index];
			}

			vint ListViewItemBindableProvider::GetColumnCount()
			{
				return columns.Count();
			}

			WString ListViewItemBindableProvider::GetColumnText(vint index)
			{
				if (index < 0 || index >= columns.Count())
				{
					return L"";
				}
				else
				{
					return columns[index]->GetText();
				}
			}

			// ===================== list::ListViewColumnItemArranger::IColumnItemView =====================

			bool ListViewItemBindableProvider::AttachCallback(IColumnItemViewCallback* value)
			{
				if(columnItemViewCallbacks.Contains(value))
				{
					return false;
				}
				else
				{
					columnItemViewCallbacks.Add(value);
					return true;
				}
			}

			bool ListViewItemBindableProvider::DetachCallback(IColumnItemViewCallback* value)
			{
				vint index = columnItemViewCallbacks.IndexOf(value);
				if (index == -1)
				{
					return false;
				}
				else
				{
					columnItemViewCallbacks.Remove(value);
					return true;
				}
			}

			vint ListViewItemBindableProvider::GetColumnSize(vint index)
			{
				return columns[index]->GetSize();
			}

			void ListViewItemBindableProvider::SetColumnSize(vint index, vint value)
			{
				columns[index]->SetSize(value);
			}

			GuiMenu* ListViewItemBindableProvider::GetDropdownPopup(vint index)
			{
				return columns[index]->GetDropdownPopup();
			}

			ColumnSortingState ListViewItemBindableProvider::GetSortingState(vint index)
			{
				return columns[index]->GetSortingState();
			}

/***********************************************************************
TreeViewItemBindableNode
***********************************************************************/

			Ptr<description::IValueReadonlyList> TreeViewItemBindableNode::PrepareValueList(const description::Value& inputItemSource)
			{
				if (auto value = ReadProperty(inputItemSource, rootProvider->childrenProperty))
				{
					if (auto ol = value.Cast<IValueObservableList>())
					{
						return ol;
					}
					else if (auto rl = value.Cast<IValueReadonlyList>())
					{
						return rl;
					}
					else
					{
						return IValueList::Create(GetLazyList<Value>(value));
					}
				}
				else
				{
					return IValueList::Create();
				}
			}

			void TreeViewItemBindableNode::PrepareChildren(Ptr<description::IValueReadonlyList> newValueList)
			{
				if (!childrenVirtualList)
				{
					childrenVirtualList = newValueList;
					if (auto ol = childrenVirtualList.Cast<IValueObservableList>())
					{
						itemChangedEventHandler = ol->ItemChanged.Add([this](vint start, vint oldCount, vint newCount)
						{
							callback->OnBeforeItemModified(this, start, oldCount, newCount, true);
							children.RemoveRange(start, oldCount);
							for (vint i = 0; i < newCount; i++)
							{
								Value value = childrenVirtualList->Get(start + i);
								auto node = Ptr(new TreeViewItemBindableNode(value, this));
								children.Insert(start + i, node);
							}
							callback->OnAfterItemModified(this, start, oldCount, newCount, true);
						});
					}

					vint count = childrenVirtualList->GetCount();
					for (vint i = 0; i < count; i++)
					{
						Value value = childrenVirtualList->Get(i);
						auto node = Ptr(new TreeViewItemBindableNode(value, this));
						children.Add(node);
					}
				}
			}

			void TreeViewItemBindableNode::UnprepareChildren()
			{
				if (itemChangedEventHandler)
				{
					auto ol = childrenVirtualList.Cast<IValueObservableList>();
					ol->ItemChanged.Remove(itemChangedEventHandler);
					itemChangedEventHandler = nullptr;
				}
				childrenVirtualList = nullptr;
				for (auto node : children)
				{
					node->UnprepareChildren();
				}
				children.Clear();
			}

			void TreeViewItemBindableNode::PrepareReverseMapping()
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::TreeViewItemBindableNode::PrepareReverseMapping()#"
				if (rootProvider->reverseMappingProperty && !itemSource.IsNull())
				{
					auto oldValue = ReadProperty(itemSource, rootProvider->reverseMappingProperty);
					CHECK_ERROR(oldValue.IsNull(), ERROR_MESSAGE_PREFIX L"The reverse mapping property of an item has been unexpectedly changed.");
					WriteProperty(itemSource, rootProvider->reverseMappingProperty, Value::From(this));
				}
#undef ERROR_MESSAGE_PREFIX
			}

			void TreeViewItemBindableNode::UnprepareReverseMapping()
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::TreeViewItemBindableNode::PrepareReverseMapping()#"
				if (rootProvider->reverseMappingProperty && !itemSource.IsNull())
				{
					auto oldValue = ReadProperty(itemSource, rootProvider->reverseMappingProperty);
					CHECK_ERROR(oldValue.GetRawPtr() == this, ERROR_MESSAGE_PREFIX L"The reverse mapping property of an item has been unexpectedly changed.");
					WriteProperty(itemSource, rootProvider->reverseMappingProperty, {});
				}
#undef ERROR_MESSAGE_PREFIX
			}

			TreeViewItemBindableNode::TreeViewItemBindableNode(const description::Value& _itemSource, TreeViewItemBindableNode* _parent)
				:itemSource(_itemSource)
				, rootProvider(_parent->rootProvider)
				, parent(_parent)
				, callback(_parent->callback)
			{
				PrepareReverseMapping();
			}

			TreeViewItemBindableNode::TreeViewItemBindableNode(TreeViewItemBindableRootProvider* _rootProvider)
				:rootProvider(_rootProvider)
				, parent(nullptr)
				, callback(_rootProvider)
			{
			}

			TreeViewItemBindableNode::~TreeViewItemBindableNode()
			{
				UnprepareReverseMapping();
				if (itemChangedEventHandler)
				{
					auto ol = childrenVirtualList.Cast<IValueObservableList>();
					ol->ItemChanged.Remove(itemChangedEventHandler);
				}
			}

			description::Value TreeViewItemBindableNode::GetItemSource()
			{
				return itemSource;
			}

			void TreeViewItemBindableNode::SetItemSource(const description::Value& _itemSource)
			{
				auto newVirtualList = PrepareValueList(_itemSource);
				vint oldCount = childrenVirtualList ? childrenVirtualList->GetCount() : 0;
				vint newCount = newVirtualList->GetCount();

				callback->OnBeforeItemModified(this, 0, oldCount, newCount, true);
				UnprepareChildren();
				UnprepareReverseMapping();
				itemSource = _itemSource;
				PrepareReverseMapping();
				PrepareChildren(newVirtualList);
				callback->OnAfterItemModified(this, 0, oldCount, newCount, true);
			}

			bool TreeViewItemBindableNode::GetExpanding()
			{
				return this == rootProvider->rootNode.Obj() ? true : expanding;
			}

			void TreeViewItemBindableNode::SetExpanding(bool value)
			{
				if (this != rootProvider->rootNode.Obj() && expanding != value)
				{
					expanding = value;
					if (expanding)
					{
						callback->OnItemExpanded(this);
					}
					else
					{
						callback->OnItemCollapsed(this);
					}
				}
			}

			vint TreeViewItemBindableNode::CalculateTotalVisibleNodes()
			{
				if (!GetExpanding())
				{
					return 1;
				}

				if (!childrenVirtualList)
				{
					PrepareChildren(PrepareValueList(itemSource));
				}
				vint count = 1;
				for (auto child : children)
				{
					count += child->CalculateTotalVisibleNodes();
				}
				return count;
			}

			void TreeViewItemBindableNode::NotifyDataModified()
			{
				if (parent)
				{
					vint index = parent->children.IndexOf(this);
					callback->OnBeforeItemModified(parent, index, 1, 1, false);
					callback->OnAfterItemModified(parent, index, 1, 1, false);
				}
			}

			vint TreeViewItemBindableNode::GetChildCount()
			{
				if (!childrenVirtualList)
				{
					PrepareChildren(PrepareValueList(itemSource));
				}
				return children.Count();
			}

			Ptr<tree::INodeProvider> TreeViewItemBindableNode::GetParent()
			{
				return Ptr(parent);
			}

			Ptr<tree::INodeProvider> TreeViewItemBindableNode::GetChild(vint index)
			{
				if (!childrenVirtualList)
				{
					PrepareChildren(PrepareValueList(itemSource));
				}
				if (0 <= index && index < children.Count())
				{
					return children[index];
				}
				return nullptr;
			}

/***********************************************************************
TreeViewItemBindableRootProvider
***********************************************************************/

			TreeViewItemBindableRootProvider::TreeViewItemBindableRootProvider()
			{
				rootNode = Ptr(new TreeViewItemBindableNode(this));
			}

			TreeViewItemBindableRootProvider::~TreeViewItemBindableRootProvider()
			{
			}

			description::Value TreeViewItemBindableRootProvider::GetItemSource()
			{
				return rootNode->GetItemSource();
			}

			void TreeViewItemBindableRootProvider::SetItemSource(const description::Value& _itemSource)
			{
				rootNode->SetItemSource(_itemSource);
			}

			void TreeViewItemBindableRootProvider::UpdateBindingProperties(bool updateChildrenProperty)
			{
				vint oldCount = rootNode->GetChildCount();
				if (updateChildrenProperty)
				{
					rootNode->UnprepareChildren();
				}
				vint newCount = rootNode->GetChildCount();
				OnBeforeItemModified(rootNode.Obj(), 0, oldCount, newCount, updateChildrenProperty);
				OnAfterItemModified(rootNode.Obj(), 0, oldCount, newCount, updateChildrenProperty);
			}

			// ===================== tree::INodeRootProvider =====================

			Ptr<tree::INodeProvider> TreeViewItemBindableRootProvider::GetRootNode()
			{
				return rootNode;
			}

			WString TreeViewItemBindableRootProvider::GetTextValue(tree::INodeProvider* node)
			{
				return ReadProperty(GetBindingValue(node), textProperty);
			}

			description::Value TreeViewItemBindableRootProvider::GetBindingValue(tree::INodeProvider* node)
			{
				if (auto itemSourceNode = dynamic_cast<TreeViewItemBindableNode*>(node))
				{
					return itemSourceNode->GetItemSource();
				}
				return Value();
			}

			IDescriptable* TreeViewItemBindableRootProvider::RequestView(const WString& identifier)
			{
				if(identifier==ITreeViewItemView::Identifier)
				{
					return (ITreeViewItemView*)this;
				}
				else
				{
					return 0;
				}
			}

			// ===================== tree::ITreeViewItemView =====================

			Ptr<GuiImageData> TreeViewItemBindableRootProvider::GetNodeImage(tree::INodeProvider* node)
			{
				if (auto itemSourceNode = dynamic_cast<TreeViewItemBindableNode*>(node))
				{
					return ReadProperty(itemSourceNode->GetItemSource(), imageProperty);
				}
				return nullptr;
			}
		}
	}
}


/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\ITEMPROVIDER_ILISTVIEWITEMVIEW.CPP
***********************************************************************/

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

	const wchar_t* const IListViewItemView::Identifier = L"vl::presentation::controls::list::IListViewItemView";
	const wchar_t* const IColumnItemView::Identifier = L"vl::presentation::controls::list::IColumnItemView";

/***********************************************************************
ListViewSubItems
***********************************************************************/

	void ListViewSubItems::NotifyUpdateInternal(vint start, vint count, vint newCount)
	{
		owner->NotifyUpdate();
	}

/***********************************************************************
ListViewItem
***********************************************************************/

	void ListViewItem::NotifyUpdate()
	{
		if (owner)
		{
			vint index = owner->IndexOf(this);
			owner->InvokeOnItemModified(index, 1, 1, false);
		}
	}

	ListViewItem::ListViewItem()
		:owner(0)
	{
		subItems.owner = this;
	}

	ListViewSubItems& ListViewItem::GetSubItems()
	{
		return subItems;
	}

	Ptr<GuiImageData> ListViewItem::GetSmallImage()
	{
		return smallImage;
	}

	void ListViewItem::SetSmallImage(Ptr<GuiImageData> value)
	{
		smallImage = value;
		NotifyUpdate();
	}

	Ptr<GuiImageData> ListViewItem::GetLargeImage()
	{
		return largeImage;
	}
	
	void ListViewItem::SetLargeImage(Ptr<GuiImageData> value)
	{
		largeImage = value;
		NotifyUpdate();
	}

	const WString& ListViewItem::GetText()
	{
		return text;
	}

	void ListViewItem::SetText(const WString& value)
	{
		text = value;
		NotifyUpdate();
	}

	description::Value ListViewItem::GetTag()
	{
		return tag;
	}

	void ListViewItem::SetTag(const description::Value& value)
	{
		tag = value;
		NotifyUpdate();
	}

/***********************************************************************
ListViewColumn
***********************************************************************/

	void ListViewColumn::NotifyRebuilt()
	{
		if (owner)
		{
			vint index = owner->IndexOf(this);
			if (index != -1)
			{
				owner->NotifyColumnRebuilt(index);
			}
		}
	}

	void ListViewColumn::NotifyChanged(bool needToRefreshItems)
	{
		if (owner)
		{
			vint index = owner->IndexOf(this);
			if (index != -1)
			{
				owner->NotifyColumnChanged(index, needToRefreshItems);
			}
		}
	}

	ListViewColumn::ListViewColumn(const WString& _text, vint _size)
		:text(_text)
		,size(_size)
	{
	}

	ListViewColumn::~ListViewColumn()
	{
		if (dropdownPopup && ownPopup)
		{
			SafeDeleteControl(dropdownPopup);
		}
	}

	const WString& ListViewColumn::GetText()
	{
		return text;
	}

	void ListViewColumn::SetText(const WString& value)
	{
		if (text != value)
		{
			text = value;
			NotifyChanged(false);
		}
	}

	ItemProperty<WString> ListViewColumn::GetTextProperty()
	{
		return textProperty;
	}

	void ListViewColumn::SetTextProperty(const ItemProperty<WString>& value)
	{
		textProperty = value;
		NotifyChanged(true);
	}

	vint ListViewColumn::GetSize()
	{
		return size;
	}

	void ListViewColumn::SetSize(vint value)
	{
		if (size != value)
		{
			size = value;
			NotifyChanged(true);
		}
	}

	bool ListViewColumn::GetOwnPopup()
	{
		return ownPopup;
	}

	void ListViewColumn::SetOwnPopup(bool value)
	{
		ownPopup = value;
	}

	GuiMenu* ListViewColumn::GetDropdownPopup()
	{
		return dropdownPopup;
	}

	void ListViewColumn::SetDropdownPopup(GuiMenu* value)
	{
		if (dropdownPopup != value)
		{
			dropdownPopup = value;
			NotifyChanged(false);
		}
	}

	ColumnSortingState ListViewColumn::GetSortingState()
	{
		return sortingState;
	}

	void ListViewColumn::SetSortingState(ColumnSortingState value)
	{
		if (sortingState != value)
		{
			sortingState = value;
			NotifyChanged(false);
		}
	}

/***********************************************************************
ListViewDataColumns
***********************************************************************/

	void ListViewDataColumns::NotifyUpdateInternal(vint start, vint count, vint newCount)
	{
		itemProvider->RefreshAllItems();
	}

	ListViewDataColumns::ListViewDataColumns(IListViewItemProvider* _itemProvider)
		:itemProvider(_itemProvider)
	{
	}

	ListViewDataColumns::~ListViewDataColumns()
	{
	}

/***********************************************************************
ListViewColumns
***********************************************************************/

	void ListViewColumns::NotifyColumnRebuilt(vint column)
	{
		NotifyUpdate(column, 1);
	}

	void ListViewColumns::NotifyColumnChanged(vint column, bool needToRefreshItems)
	{
		itemProvider->NotifyColumnChanged();
	}

	void ListViewColumns::BeforeInsert(vint index, const Ptr<ListViewColumn>& value)
	{
		// Check if this column is already in the provider
		if (value->owner)
		{
			throw ArgumentException(L"The ListViewColumn is already belong to a ListViewColumns.", L"vl::presentation::controls::list::ListViewColumns::BeforeInsert", L"value");
		}
	}

	void ListViewColumns::AfterInsert(vint index, const Ptr<ListViewColumn>& value)
	{
		collections::ObservableListBase<Ptr<ListViewColumn>>::AfterInsert(index, value);
		value->owner = this;
	}

	void ListViewColumns::BeforeRemove(vint index, const Ptr<ListViewColumn>& value)
	{
		value->owner = 0;
		collections::ObservableListBase<Ptr<ListViewColumn>>::BeforeRemove(index, value);
	}

	void ListViewColumns::NotifyUpdateInternal(vint start, vint count, vint newCount)
	{
		itemProvider->NotifyColumnRebuilt();
	}

	ListViewColumns::ListViewColumns(IListViewItemProvider* _itemProvider)
		:itemProvider(_itemProvider)
	{
	}

	ListViewColumns::~ListViewColumns()
	{
	}

/***********************************************************************
ListViewItemProvider
***********************************************************************/

	void ListViewItemProvider::BeforeInsert(vint index, const Ptr<ListViewItem>& value)
	{
		// Check if this item is already in the provider
		if (value->owner)
		{
			throw ArgumentException(L"The ListViewItem is already belong to a ListViewItemProvider.", L"vl::presentation::controls::list::ListViewItemProvider::BeforeInsert", L"value");
		}
	}

	void ListViewItemProvider::AfterInsert(vint index, const Ptr<ListViewItem>& value)
	{
		ListProvider<Ptr<ListViewItem>>::AfterInsert(index, value);
		value->owner = this;
	}

	void ListViewItemProvider::BeforeRemove(vint index, const Ptr<ListViewItem>& value)
	{
		value->owner = 0;
		ListProvider<Ptr<ListViewItem>>::AfterInsert(index, value);
	}

	void ListViewItemProvider::RebuildAllItems()
	{
		InvokeOnItemModified(0, Count(), Count(), true);
	}

	void ListViewItemProvider::RefreshAllItems()
	{
		InvokeOnItemModified(0, Count(), Count(), false);
	}

	void ListViewItemProvider::NotifyColumnRebuilt()
	{
		for (auto callback : columnItemViewCallbacks)
		{
			callback->OnColumnRebuilt();
		}
		RefreshAllItems();
	}

	void ListViewItemProvider::NotifyColumnChanged()
	{
		for (auto callback : columnItemViewCallbacks)
		{
			callback->OnColumnChanged(true);
		}
		RefreshAllItems();
	}

	ListViewItemProvider::ListViewItemProvider()
		:columns(this)
		, dataColumns(this)
	{
	}

	ListViewItemProvider::~ListViewItemProvider()
	{
	}

	WString ListViewItemProvider::GetTextValue(vint itemIndex)
	{
		return GetText(itemIndex);
	}

	description::Value ListViewItemProvider::GetBindingValue(vint itemIndex)
	{
		return Value::From(Get(itemIndex));
	}

	IDescriptable* ListViewItemProvider::RequestView(const WString& identifier)
	{
		if (identifier == IListViewItemView::Identifier)
		{
			return (IListViewItemView*)this;
		}
		else if (identifier == IColumnItemView::Identifier)
		{
			return (IColumnItemView*)this;
		}
		else
		{
			return 0;
		}
	}

	Ptr<GuiImageData> ListViewItemProvider::GetSmallImage(vint itemIndex)
	{
		return Get(itemIndex)->smallImage;
	}

	Ptr<GuiImageData> ListViewItemProvider::GetLargeImage(vint itemIndex)
	{
		return Get(itemIndex)->largeImage;
	}

	WString ListViewItemProvider::GetText(vint itemIndex)
	{
		return Get(itemIndex)->text;
	}

	WString ListViewItemProvider::GetSubItem(vint itemIndex, vint index)
	{
#define ERROR_MESSAGE_PREFIX L"ListViewItemProvider::GetSubItem(vint, vint)#"
		CHECK_ERROR(0 <= index && index < columns.Count() - 1, ERROR_MESSAGE_PREFIX L"Sub item index out of range.");
		Ptr<ListViewItem> item = Get(itemIndex);
		if (index < 0 || index >= item->GetSubItems().Count())
		{
			return WString::Empty;
		}
		else
		{
			return item->GetSubItems()[index];
		}
#undef ERROR_MESSAGE_PREFIX
	}

	vint ListViewItemProvider::GetDataColumnCount()
	{
		return dataColumns.Count();
	}

	vint ListViewItemProvider::GetDataColumn(vint index)
	{
		return dataColumns[index];
	}

	vint ListViewItemProvider::GetColumnCount()
	{
		return columns.Count();
	}

	WString ListViewItemProvider::GetColumnText(vint index)
	{
		if (index<0 || index >= columns.Count())
		{
			return L"";
		}
		else
		{
			return columns[index]->GetText();
		}
	}

	bool ListViewItemProvider::AttachCallback(IColumnItemViewCallback* value)
	{
		if(columnItemViewCallbacks.Contains(value))
		{
			return false;
		}
		else
		{
			columnItemViewCallbacks.Add(value);
			return true;
		}
	}

	bool ListViewItemProvider::DetachCallback(IColumnItemViewCallback* value)
	{
		vint index=columnItemViewCallbacks.IndexOf(value);
		if(index==-1)
		{
			return false;
		}
		else
		{
			columnItemViewCallbacks.Remove(value);
			return true;
		}
	}

	vint ListViewItemProvider::GetColumnSize(vint index)
	{
		if(index<0 || index>=columns.Count())
		{
			return 0;
		}
		else
		{
			return columns[index]->GetSize();
		}
	}

	void ListViewItemProvider::SetColumnSize(vint index, vint value)
	{
		if(index>=0 && index<columns.Count())
		{
			columns[index]->SetSize(value);
		}
	}

	GuiMenu* ListViewItemProvider::GetDropdownPopup(vint index)
	{
		if(index<0 || index>=columns.Count())
		{
			return 0;
		}
		else
		{
			return columns[index]->GetDropdownPopup();
		}
	}

	ColumnSortingState ListViewItemProvider::GetSortingState(vint index)
	{
		if (index < 0 || index >= columns.Count())
		{
			return ColumnSortingState::NotSorted;
		}
		else
		{
			return columns[index]->GetSortingState();
		}
	}

	ListViewDataColumns& ListViewItemProvider::GetDataColumns()
	{
		return dataColumns;
	}

	ListViewColumns& ListViewItemProvider::GetColumns()
	{
		return columns;
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\ITEMPROVIDER_ITEXTITEMVIEW.CPP
***********************************************************************/

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

	const wchar_t* const ITextItemView::Identifier = L"vl::presentation::controls::list::ITextItemView";

/***********************************************************************
TextItem
***********************************************************************/

	void TextItem::NotifyUpdate(bool raiseCheckEvent)
	{
		if (owner)
		{
			vint index = owner->IndexOf(this);
			owner->InvokeOnItemModified(index, 1, 1, false);

			if (raiseCheckEvent)
			{
				owner->itemProviderCallback->OnItemCheckedChanged(index);
			}
		}
	}

	TextItem::TextItem()
		:owner(0)
		, checked(false)
	{
	}

	TextItem::TextItem(const WString& _text, bool _checked)
		:owner(0)
		, text(_text)
		, checked(_checked)
	{
	}

	TextItem::~TextItem()
	{
	}

	const WString& TextItem::GetText()
	{
		return text;
	}

	void TextItem::SetText(const WString& value)
	{
		if (text != value)
		{
			text = value;
			NotifyUpdate(false);
		}
	}

	bool TextItem::GetChecked()
	{
		return checked;
	}

	void TextItem::SetChecked(bool value)
	{
		if (checked != value)
		{
			checked = value;
			NotifyUpdate(true);
		}
	}

/***********************************************************************
TextItemProvider
***********************************************************************/

	void TextItemProvider::BeforeInsert(vint item, const Ptr<TextItem>& value)
	{
		// Check if this item is already in the provider
		if (value->owner)
		{
			throw ArgumentException(L"The TextItem is already belog to a TextItemProvider.", L"vl::presentation::controls::list::TextItemProvider::BeforeInsert", L"value");
		}
	}

	void TextItemProvider::AfterInsert(vint item, const Ptr<TextItem>& value)
	{
		ListProvider<Ptr<TextItem>>::AfterInsert(item, value);
		value->owner = this;
	}

	void TextItemProvider::BeforeRemove(vint item, const Ptr<TextItem>& value)
	{
		value->owner = 0;
		ListProvider<Ptr<TextItem>>::BeforeRemove(item, value);
	}

	WString TextItemProvider::GetTextValue(vint itemIndex)
	{
		return Get(itemIndex)->GetText();
	}

	description::Value TextItemProvider::GetBindingValue(vint itemIndex)
	{
		return Value::From(Get(itemIndex));
	}

	bool TextItemProvider::GetChecked(vint itemIndex)
	{
		return Get(itemIndex)->GetChecked();
	}

	void TextItemProvider::SetChecked(vint itemIndex, bool value)
	{
		return Get(itemIndex)->SetChecked(value);
	}

	TextItemProvider::TextItemProvider(ITextItemProviderCallback* _itemProviderCallback)
		:itemProviderCallback(_itemProviderCallback)
	{
	}

	TextItemProvider::~TextItemProvider()
	{
	}

	IDescriptable* TextItemProvider::RequestView(const WString& identifier)
	{
		if (identifier == ITextItemView::Identifier)
		{
			return (ITextItemView*)this;
		}
		else
		{
			return nullptr;
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\ITEMPROVIDER_ITREEVIEWITEMVIEW.CPP
***********************************************************************/

namespace vl::presentation::controls::tree
{
	using namespace reflection::description;

	const wchar_t* const ITreeViewItemView::Identifier = L"vl::presentation::controls::tree::ITreeViewItemView";

/***********************************************************************
TreeViewItem
***********************************************************************/

	TreeViewItem::TreeViewItem()
	{
	}

	TreeViewItem::TreeViewItem(const Ptr<GuiImageData>& _image, const WString& _text)
		:image(_image)
		,text(_text)
	{
	}

/***********************************************************************
TreeViewItemRootProvider
***********************************************************************/

	TreeViewItemRootProvider::TreeViewItemRootProvider()
	{
	}

	TreeViewItemRootProvider::~TreeViewItemRootProvider()
	{
	}

	Ptr<TreeViewItem> TreeViewItemRootProvider::GetTreeViewData(INodeProvider* node)
	{
		MemoryNodeProvider* memoryNode=GetMemoryNode(node);
		if(memoryNode)
		{
			return memoryNode->GetData().Cast<TreeViewItem>();
		}
		else
		{
			return 0;
		}
	}

	void TreeViewItemRootProvider::SetTreeViewData(INodeProvider* node, Ptr<TreeViewItem> value)
	{
		MemoryNodeProvider* memoryNode=GetMemoryNode(node);
		if(memoryNode)
		{
			memoryNode->SetData(value);
		}
	}
	
	void TreeViewItemRootProvider::UpdateTreeViewData(INodeProvider* node)
	{
		MemoryNodeProvider* memoryNode=GetMemoryNode(node);
		if(memoryNode)
		{
			memoryNode->NotifyDataModified();
		}
	}

	Ptr<GuiImageData> TreeViewItemRootProvider::GetNodeImage(INodeProvider* node)
	{
		MemoryNodeProvider* memoryNode = dynamic_cast<MemoryNodeProvider*>(node);
		if (memoryNode)
		{
			Ptr<TreeViewItem> data = memoryNode->GetData().Cast<TreeViewItem>();
			if (data)
			{
				return data->image;
			}
		}
		return 0;
	}

	WString TreeViewItemRootProvider::GetTextValue(INodeProvider* node)
	{
		MemoryNodeProvider* memoryNode = dynamic_cast<MemoryNodeProvider*>(node);
		if (memoryNode)
		{
			Ptr<TreeViewItem> data = memoryNode->GetData().Cast<TreeViewItem>();
			if (data)
			{
				return data->text;
			}
		}
		return L"";
	}

	description::Value TreeViewItemRootProvider::GetBindingValue(INodeProvider* node)
	{
		return Value::From(GetTreeViewData(node));
	}

	IDescriptable* TreeViewItemRootProvider::RequestView(const WString& identifier)
	{
		if (identifier == ITreeViewItemView::Identifier)
		{
			return (ITreeViewItemView*)this;
		}
		else
		{
			return MemoryNodeRootProvider::RequestView(identifier);
		}
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\ITEMTEMPLATE_ILISTVIEWITEMVIEW.CPP
***********************************************************************/

namespace vl::presentation::controls::list
{
	using namespace elements;
	using namespace compositions;
	using namespace collections;
	using namespace reflection::description;

/***********************************************************************
DefaultListViewItemTemplate
***********************************************************************/

	DefaultListViewItemTemplate::DefaultListViewItemTemplate()
	{
		SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
	}

	DefaultListViewItemTemplate::~DefaultListViewItemTemplate()
	{
	}

/***********************************************************************
BigIconListViewItemTemplate
***********************************************************************/

	void BigIconListViewItemTemplate::OnInitialize()
	{
		{
			auto table = new GuiTableComposition;
			AddChild(table);
			table->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
			table->SetRowsAndColumns(2, 3);
			table->SetRowOption(0, GuiCellOption::MinSizeOption());
			table->SetRowOption(1, GuiCellOption::MinSizeOption());
			table->SetColumnOption(0, GuiCellOption::PercentageOption(0.5));
			table->SetColumnOption(1, GuiCellOption::MinSizeOption());
			table->SetColumnOption(2, GuiCellOption::PercentageOption(0.5));
			table->SetAlignmentToParent(Margin(0, 0, 0, 0));
			table->SetCellPadding(5);
			{
				auto cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(0, 1, 1, 1);
				cell->SetPreferredMinSize(Size(32, 32));

				image = GuiImageFrameElement::Create();
				image->SetStretch(true);
				cell->SetOwnedElement(Ptr(image));
			}
			{
				auto cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetMinSizeLimitation(GuiGraphicsComposition::NoLimit);
				cell->SetSite(1, 0, 1, 3);
				cell->SetPreferredMinSize(Size(64, 40));

				text = GuiSolidLabelElement::Create();
				text->SetAlignments(Alignment::Center, Alignment::Top);
				text->SetWrapLine(true);
				text->SetEllipse(true);
				cell->SetOwnedElement(Ptr(text));
			}
		}

		FontChanged.AttachMethod(this, &BigIconListViewItemTemplate::OnFontChanged);
		FontChanged.Execute(compositions::GuiEventArgs(this));
	}

	void BigIconListViewItemTemplate::OnRefresh()
	{
		if (auto view = dynamic_cast<IListViewItemView*>(listControl->GetItemProvider()->RequestView(WString::Unmanaged(IListViewItemView::Identifier))))
		{
			auto itemIndex = GetIndex();
			auto imageData = view->GetLargeImage(itemIndex);
			if (imageData)
			{
				image->SetImage(imageData->GetImage(), imageData->GetFrameIndex());
			}
			else
			{
				image->SetImage(nullptr);
			}
			text->SetText(view->GetText(itemIndex));

			if (auto controlTemplate = dynamic_cast<templates::GuiListViewTemplate*>(listControl->TypedControlTemplateObject(true)))
			{
				text->SetColor(controlTemplate->GetPrimaryTextColor());
			}
		}
	}

	void BigIconListViewItemTemplate::OnFontChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		text->SetFont(GetFont());
	}

	BigIconListViewItemTemplate::BigIconListViewItemTemplate()
	{
	}

	BigIconListViewItemTemplate::~BigIconListViewItemTemplate()
	{
	}

/***********************************************************************
SmallIconListViewItemTemplate
***********************************************************************/

	void SmallIconListViewItemTemplate::OnInitialize()
	{
		{
			auto table = new GuiTableComposition;
			AddChild(table);
			table->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
			table->SetRowsAndColumns(3, 2);
			table->SetRowOption(0, GuiCellOption::PercentageOption(0.5));
			table->SetRowOption(1, GuiCellOption::MinSizeOption());
			table->SetRowOption(2, GuiCellOption::PercentageOption(0.5));
			table->SetColumnOption(0, GuiCellOption::MinSizeOption());
			table->SetColumnOption(1, GuiCellOption::MinSizeOption());
			table->SetAlignmentToParent(Margin(0, 0, 0, 0));
			table->SetCellPadding(2);
			{
				GuiCellComposition* cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(1, 0, 1, 1);
				cell->SetPreferredMinSize(Size(16, 16));

				image = GuiImageFrameElement::Create();
				image->SetStretch(true);
				cell->SetOwnedElement(Ptr(image));
			}
			{
				GuiCellComposition* cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(0, 1, 3, 1);
				cell->SetPreferredMinSize(Size(192, 0));

				text = GuiSolidLabelElement::Create();
				text->SetAlignments(Alignment::Left, Alignment::Center);
				text->SetEllipse(true);
				cell->SetOwnedElement(Ptr(text));
			}
		}

		FontChanged.AttachMethod(this, &SmallIconListViewItemTemplate::OnFontChanged);
		FontChanged.Execute(compositions::GuiEventArgs(this));
	}

	void SmallIconListViewItemTemplate::OnRefresh()
	{
		if (auto view = dynamic_cast<IListViewItemView*>(listControl->GetItemProvider()->RequestView(WString::Unmanaged(IListViewItemView::Identifier))))
		{
			auto itemIndex = GetIndex();
			auto imageData = view->GetSmallImage(itemIndex);
			if (imageData)
			{
				image->SetImage(imageData->GetImage(), imageData->GetFrameIndex());
			}
			else
			{
				image->SetImage(nullptr);
			}
			text->SetText(view->GetText(itemIndex));

			if (auto controlTemplate = dynamic_cast<templates::GuiListViewTemplate*>(listControl->TypedControlTemplateObject(true)))
			{
				text->SetColor(controlTemplate->GetPrimaryTextColor());
			}
		}
	}

	void SmallIconListViewItemTemplate::OnFontChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		text->SetFont(GetFont());
	}

	SmallIconListViewItemTemplate::SmallIconListViewItemTemplate()
	{
	}

	SmallIconListViewItemTemplate::~SmallIconListViewItemTemplate()
	{
	}

/***********************************************************************
ListListViewItemTemplate
***********************************************************************/

	void ListListViewItemTemplate::OnInitialize()
	{
		{
			auto table = new GuiTableComposition;
			AddChild(table);
			table->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
			table->SetRowsAndColumns(3, 2);
			table->SetRowOption(0, GuiCellOption::PercentageOption(0.5));
			table->SetRowOption(1, GuiCellOption::MinSizeOption());
			table->SetRowOption(2, GuiCellOption::PercentageOption(0.5));
			table->SetColumnOption(0, GuiCellOption::MinSizeOption());
			table->SetColumnOption(1, GuiCellOption::MinSizeOption());
			table->SetAlignmentToParent(Margin(0, 0, 0, 0));
			table->SetCellPadding(2);
			{
				auto cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(1, 0, 1, 1);
				cell->SetPreferredMinSize(Size(16, 16));

				image = GuiImageFrameElement::Create();
				image->SetStretch(true);
				cell->SetOwnedElement(Ptr(image));
			}
			{
				auto cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(0, 1, 3, 1);

				auto textBounds = new GuiBoundsComposition;
				cell->AddChild(textBounds);
				textBounds->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElement);
				textBounds->SetAlignmentToParent(Margin(0, 0, 16, 0));

				text = GuiSolidLabelElement::Create();
				text->SetAlignments(Alignment::Left, Alignment::Center);
				textBounds->SetOwnedElement(Ptr(text));
			}
		}

		FontChanged.AttachMethod(this, &ListListViewItemTemplate::OnFontChanged);
		FontChanged.Execute(compositions::GuiEventArgs(this));
	}

	void ListListViewItemTemplate::OnRefresh()
	{
		if (auto view = dynamic_cast<IListViewItemView*>(listControl->GetItemProvider()->RequestView(WString::Unmanaged(IListViewItemView::Identifier))))
		{
			auto itemIndex = GetIndex();
			auto imageData = view->GetSmallImage(itemIndex);
			if (imageData)
			{
				image->SetImage(imageData->GetImage(), imageData->GetFrameIndex());
			}
			else
			{
				image->SetImage(nullptr);
			}
			text->SetText(view->GetText(itemIndex));

			if (auto controlTemplate = dynamic_cast<templates::GuiListViewTemplate*>(listControl->TypedControlTemplateObject(true)))
			{
				text->SetColor(controlTemplate->GetPrimaryTextColor());
			}
		}
	}

	void ListListViewItemTemplate::OnFontChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		text->SetFont(GetFont());
	}

	ListListViewItemTemplate::ListListViewItemTemplate()
	{
	}

	ListListViewItemTemplate::~ListListViewItemTemplate()
	{
	}

/***********************************************************************
TileListViewItemTemplate
***********************************************************************/

	elements::GuiSolidLabelElement* TileListViewItemTemplate::CreateTextElement(vint textRow)
	{
		auto cell = new GuiCellComposition;
		textTable->AddChild(cell);
		cell->SetSite(textRow + 1, 0, 1, 1);

		auto textElement = Ptr(GuiSolidLabelElement::Create());
		textElement->SetAlignments(Alignment::Left, Alignment::Center);
		textElement->SetEllipse(true);
		cell->SetOwnedElement(textElement);
		return textElement.Obj();
	}

	void TileListViewItemTemplate::ResetTextTable(vint dataColumnCount)
	{
		if (text && dataTexts.Count() == dataColumnCount) return;
		for (vint i = textTable->Children().Count() - 1; i >= 0; i--)
		{
			if (auto cell = dynamic_cast<GuiCellComposition*>(textTable->Children()[i]))
			{
				SafeDeleteComposition(cell);
			}
		}

		{
			vint textRows = dataColumnCount + 1;
			textTable->SetRowsAndColumns(textRows + 2, 1);
			textTable->SetRowOption(0, GuiCellOption::PercentageOption(0.5));
			for (vint i = 0; i < textRows; i++)
			{
				textTable->SetRowOption(i + 1, GuiCellOption::MinSizeOption());
			}
			textTable->SetRowOption(textRows + 1, GuiCellOption::PercentageOption(0.5));
			textTable->SetColumnOption(0, GuiCellOption::PercentageOption(1.0));
		}

		text = CreateTextElement(0);
		text->SetFont(GetFont());
		{
			dataTexts.Resize(dataColumnCount);
			for (vint i = 0; i < dataColumnCount; i++)
			{
				dataTexts[i] = CreateTextElement(i + 1);
				dataTexts[i]->SetFont(GetFont());
			}
		}
	}

	void TileListViewItemTemplate::OnInitialize()
	{
		{
			auto table = new GuiTableComposition;
			AddChild(table);
			table->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
			table->SetRowsAndColumns(3, 2);
			table->SetRowOption(0, GuiCellOption::PercentageOption(0.5));
			table->SetRowOption(1, GuiCellOption::MinSizeOption());
			table->SetRowOption(2, GuiCellOption::PercentageOption(0.5));
			table->SetColumnOption(0, GuiCellOption::MinSizeOption());
			table->SetColumnOption(1, GuiCellOption::MinSizeOption());
			table->SetAlignmentToParent(Margin(0, 0, 0, 0));
			table->SetCellPadding(4);
			{
				auto cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(1, 0, 1, 1);
				cell->SetPreferredMinSize(Size(32, 32));

				image = GuiImageFrameElement::Create();
				image->SetStretch(true);
				cell->SetOwnedElement(Ptr(image));
			}
			{
				auto cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(0, 1, 3, 1);
				cell->SetPreferredMinSize(Size(224, 0));

				textTable = new GuiTableComposition;
				textTable->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				textTable->SetCellPadding(1);
				textTable->SetAlignmentToParent(Margin(0, 0, 0, 0));
				cell->AddChild(textTable);
			}
		}

		ResetTextTable(0);
		FontChanged.AttachMethod(this, &TileListViewItemTemplate::OnFontChanged);
		FontChanged.Execute(compositions::GuiEventArgs(this));
	}

	void TileListViewItemTemplate::OnRefresh()
	{
		if (auto view = dynamic_cast<IListViewItemView*>(listControl->GetItemProvider()->RequestView(WString::Unmanaged(IListViewItemView::Identifier))))
		{
			auto itemIndex = GetIndex();
			auto imageData = view->GetLargeImage(itemIndex);
			if (imageData)
			{
				image->SetImage(imageData->GetImage(), imageData->GetFrameIndex());
			}
			else
			{
				image->SetImage(nullptr);
			}

			vint subColumnCount = view->GetColumnCount() - 1;
			vint dataColumnCount = view->GetDataColumnCount();
			if (dataColumnCount > subColumnCount) dataColumnCount = subColumnCount;
			if (dataColumnCount < 0) dataColumnCount = 0;
			ResetTextTable(dataColumnCount);

			text->SetText(view->GetText(itemIndex));
			for (vint i = 0; i < dataColumnCount; i++)
			{
				dataTexts[i]->SetText(view->GetSubItem(itemIndex, view->GetDataColumn(i)));
			}

			if (auto controlTemplate = dynamic_cast<templates::GuiListViewTemplate*>(listControl->TypedControlTemplateObject(true)))
			{
				text->SetColor(controlTemplate->GetPrimaryTextColor());
				for (vint i = 0; i < dataColumnCount; i++)
				{
					dataTexts[i]->SetText(view->GetSubItem(itemIndex, view->GetDataColumn(i)));
					dataTexts[i]->SetColor(controlTemplate->GetSecondaryTextColor());
				}
			}
		}
	}

	void TileListViewItemTemplate::OnFontChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		if (text) text->SetFont(GetFont());
		for (auto dataText : dataTexts)
		{
			dataText->SetFont(GetFont());
		}
	}

	TileListViewItemTemplate::TileListViewItemTemplate()
	{
	}

	TileListViewItemTemplate::~TileListViewItemTemplate()
	{
	}

/***********************************************************************
InformationListViewItemTemplate
***********************************************************************/

	void InformationListViewItemTemplate::ResetTextTable(vint dataColumnCount)
	{
		if (dataTexts.Count() == dataColumnCount) return;
		for (vint i = textTable->Children().Count() - 1; i >= 0; i--)
		{
			if (auto cell = dynamic_cast<GuiCellComposition*>(textTable->Children()[i]))
			{
				SafeDeleteComposition(cell);
			}
		}

		{
			textTable->SetRowsAndColumns(dataColumnCount + 2, 1);
			textTable->SetRowOption(0, GuiCellOption::PercentageOption(0.5));
			for (vint i = 0; i < dataColumnCount; i++)
			{
				textTable->SetRowOption(i + 1, GuiCellOption::MinSizeOption());
			}
			textTable->SetRowOption(dataColumnCount + 1, GuiCellOption::PercentageOption(0.5));
			textTable->SetColumnOption(0, GuiCellOption::PercentageOption(1.0));
		}

		columnTexts.Resize(dataColumnCount);
		dataTexts.Resize(dataColumnCount);

		for (vint i = 0; i < dataColumnCount; i++)
		{
			auto cell = new GuiCellComposition;
			textTable->AddChild(cell);
			cell->SetSite(i + 1, 0, 1, 1);

			auto dataTable = new GuiTableComposition;
			dataTable->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
			dataTable->SetRowsAndColumns(1, 2);
			dataTable->SetRowOption(0, GuiCellOption::MinSizeOption());
			dataTable->SetColumnOption(0, GuiCellOption::MinSizeOption());
			dataTable->SetColumnOption(1, GuiCellOption::PercentageOption(1.0));
			dataTable->SetAlignmentToParent(Margin(0, 0, 0, 0));
			cell->AddChild(dataTable);
			{
				auto cell = new GuiCellComposition;
				dataTable->AddChild(cell);
				cell->SetSite(0, 0, 1, 1);

				columnTexts[i] = GuiSolidLabelElement::Create();
				columnTexts[i]->SetFont(GetFont());
				cell->SetOwnedElement(Ptr(columnTexts[i]));
			}
			{
				auto cell = new GuiCellComposition;
				dataTable->AddChild(cell);
				cell->SetSite(0, 1, 1, 1);

				dataTexts[i] = GuiSolidLabelElement::Create();
				dataTexts[i]->SetFont(GetFont());
				dataTexts[i]->SetEllipse(true);
				cell->SetOwnedElement(Ptr(dataTexts[i]));
			}
		}
	}

	void InformationListViewItemTemplate::OnInitialize()
	{
		{
			bottomLine = GuiSolidBackgroundElement::Create();
			bottomLineComposition = new GuiBoundsComposition;
			bottomLineComposition->SetOwnedElement(Ptr(bottomLine));
			bottomLineComposition->SetAlignmentToParent(Margin(8, -1, 8, 0));
			bottomLineComposition->SetPreferredMinSize(Size(0, 1));
			AddChild(bottomLineComposition);

			auto table = new GuiTableComposition;
			AddChild(table);
			table->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
			table->SetRowsAndColumns(3, 3);
			table->SetRowOption(0, GuiCellOption::PercentageOption(0.5));
			table->SetRowOption(1, GuiCellOption::MinSizeOption());
			table->SetRowOption(2, GuiCellOption::PercentageOption(0.5));
			table->SetColumnOption(0, GuiCellOption::MinSizeOption());
			table->SetColumnOption(1, GuiCellOption::PercentageOption(1.0));
			table->SetColumnOption(2, GuiCellOption::MinSizeOption());
			table->SetAlignmentToParent(Margin(0, 0, 0, 0));
			table->SetCellPadding(4);
			{
				auto cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(1, 0, 1, 1);
				cell->SetPreferredMinSize(Size(32, 32));

				image = GuiImageFrameElement::Create();
				image->SetStretch(true);
				cell->SetOwnedElement(Ptr(image));
			}
			{
				auto cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(0, 1, 3, 1);

				text = GuiSolidLabelElement::Create();
				text->SetEllipse(true);
				cell->SetOwnedElement(Ptr(text));
			}
			{
				auto cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(0, 2, 3, 1);
				cell->SetPreferredMinSize(Size(224, 0));

				textTable = new GuiTableComposition;
				textTable->SetCellPadding(4);
				textTable->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				textTable->SetAlignmentToParent(Margin(0, 0, 0, 0));
				cell->AddChild(textTable);
			}
		}

		FontChanged.AttachMethod(this, &InformationListViewItemTemplate::OnFontChanged);
		FontChanged.Execute(compositions::GuiEventArgs(this));
	}

	void InformationListViewItemTemplate::OnRefresh()
	{
		if (auto view = dynamic_cast<IListViewItemView*>(listControl->GetItemProvider()->RequestView(WString::Unmanaged(IListViewItemView::Identifier))))
		{
			auto itemIndex = GetIndex();
			auto imageData = view->GetLargeImage(itemIndex);
			if (imageData)
			{
				image->SetImage(imageData->GetImage(), imageData->GetFrameIndex());
			}
			else
			{
				image->SetImage(nullptr);
			}
			text->SetText(view->GetText(itemIndex));

			vint subColumnCount = view->GetColumnCount() - 1;
			vint dataColumnCount = view->GetDataColumnCount();
			if (dataColumnCount > subColumnCount) dataColumnCount = subColumnCount;
			if (dataColumnCount < 0) dataColumnCount = 0;
			ResetTextTable(dataColumnCount);
			for (vint i = 0; i < dataColumnCount; i++)
			{
				columnTexts[i]->SetText(view->GetColumnText(view->GetDataColumn(i) + 1) + L": ");
				dataTexts[i]->SetText(view->GetSubItem(itemIndex, view->GetDataColumn(i)));
			}

			if (auto controlTemplate = dynamic_cast<templates::GuiListViewTemplate*>(listControl->TypedControlTemplateObject(true)))
			{
				text->SetColor(controlTemplate->GetPrimaryTextColor());
				bottomLine->SetColor(controlTemplate->GetItemSeparatorColor());
				for (vint i = 0; i < dataColumnCount; i++)
				{
					columnTexts[i]->SetColor(controlTemplate->GetSecondaryTextColor());
					dataTexts[i]->SetColor(controlTemplate->GetPrimaryTextColor());
				}
			}
		}
	}

	void InformationListViewItemTemplate::OnFontChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		{
			auto font = GetFont();
			font.size = (vint)(font.size * 1.2);
			text->SetFont(font);
		}

		for (auto columnText : columnTexts)
		{
			columnText->SetFont(GetFont());
		}
		for (auto dataText : dataTexts)
		{
			dataText->SetFont(GetFont());
		}
	}

	InformationListViewItemTemplate::InformationListViewItemTemplate()
	{
	}

	InformationListViewItemTemplate::~InformationListViewItemTemplate()
	{
	}

/***********************************************************************
DetailListViewItemTemplate
***********************************************************************/

	void DetailListViewItemTemplate::UpdateSubItemSize()
	{
		if (auto view = dynamic_cast<IListViewItemView*>(listControl->GetItemProvider()->RequestView(WString::Unmanaged(IListViewItemView::Identifier))))
		{
			if (columnItemView)
			{
				vint columnCount = view->GetColumnCount();
				if (columnCount > textTable->GetColumns())
				{
					columnCount = textTable->GetColumns();
				}
				for (vint i = 0; i < columnCount; i++)
				{
					textTable->SetColumnOption(i, GuiCellOption::AbsoluteOption(columnItemView->GetColumnSize(i)));
				}
			}
		}
	}

	void DetailListViewItemTemplate::ResetTextTable(vint subColumnCount)
	{
		if (subItemCells.Count() == subColumnCount) return;

		for (auto cell : subItemCells)
		{
			SafeDeleteComposition(cell);
		}
		subItemCells.Resize(subColumnCount);
		subItemTexts.Resize(subColumnCount);

		textTable->SetRowsAndColumns(1, subColumnCount + 1);
		for (vint i = 0; i < subColumnCount; i++)
		{
			auto cell = new GuiCellComposition;
			textTable->AddChild(cell);
			cell->SetSite(0, i + 1, 1, 1);

			auto textBounds = new GuiBoundsComposition;
			cell->AddChild(textBounds);
			textBounds->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElement);
			textBounds->SetAlignmentToParent(Margin(8, 0, 8, 0));

			auto subText = GuiSolidLabelElement::Create();
			subText->SetAlignments(Alignment::Left, Alignment::Center);
			subText->SetFont(GetFont());
			subText->SetEllipse(true);
			textBounds->SetOwnedElement(Ptr(subText));

			subItemCells[i] = cell;
			subItemTexts[i] = subText;
		}
	}

	void DetailListViewItemTemplate::OnInitialize()
	{
		columnItemView = dynamic_cast<IColumnItemView*>(listControl->GetItemProvider()->RequestView(WString::Unmanaged(IColumnItemView::Identifier)));

		{
			textTable = new GuiTableComposition;
			textTable->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
			textTable->SetAlignmentToParent(Margin(0, 0, 0, 0));
			textTable->SetRowsAndColumns(1, 1);
			textTable->SetRowOption(0, GuiCellOption::MinSizeOption());
			textTable->SetColumnOption(0, GuiCellOption::AbsoluteOption(0));
			AddChild(textTable);
			{
				auto cell = new GuiCellComposition;
				textTable->AddChild(cell);
				cell->SetSite(0, 0, 1, 1);

				auto table = new GuiTableComposition;
				cell->AddChild(table);
				table->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				table->SetRowsAndColumns(3, 2);
				table->SetRowOption(0, GuiCellOption::PercentageOption(0.5));
				table->SetRowOption(1, GuiCellOption::MinSizeOption());
				table->SetRowOption(2, GuiCellOption::PercentageOption(0.5));
				table->SetColumnOption(0, GuiCellOption::MinSizeOption());
				table->SetColumnOption(1, GuiCellOption::PercentageOption(1.0));
				table->SetAlignmentToParent(Margin(0, 0, 0, 0));
				table->SetCellPadding(2);
				{
					auto cell = new GuiCellComposition;
					table->AddChild(cell);
					cell->SetSite(1, 0, 1, 1);
					cell->SetPreferredMinSize(Size(16, 16));

					image = GuiImageFrameElement::Create();
					image->SetStretch(true);
					cell->SetOwnedElement(Ptr(image));
				}
				{
					auto cell = new GuiCellComposition;
					table->AddChild(cell);
					cell->SetSite(0, 1, 3, 1);

					auto textBounds = new GuiBoundsComposition;
					cell->AddChild(textBounds);
					textBounds->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElement);
					textBounds->SetAlignmentToParent(Margin(0, 0, 8, 0));

					text = GuiSolidLabelElement::Create();
					text->SetAlignments(Alignment::Left, Alignment::Center);
					text->SetFont(GetFont());
					text->SetEllipse(true);
					textBounds->SetOwnedElement(Ptr(text));
				}
			}
		}

		FontChanged.AttachMethod(this, &DetailListViewItemTemplate::OnFontChanged);
		FontChanged.Execute(compositions::GuiEventArgs(this));
	}

	void DetailListViewItemTemplate::OnRefresh()
	{
		if (auto view = dynamic_cast<IListViewItemView*>(listControl->GetItemProvider()->RequestView(WString::Unmanaged(IListViewItemView::Identifier))))
		{
			auto itemIndex = GetIndex();
			vint subColumnCount = view->GetColumnCount() - 1;
			if (subColumnCount < 0) subColumnCount = 0;
			ResetTextTable(subColumnCount);

			auto imageData = view->GetSmallImage(itemIndex);
			if (imageData)
			{
				image->SetImage(imageData->GetImage(), imageData->GetFrameIndex());
			}
			else
			{
				image->SetImage(0);
			}

			text->SetText(view->GetText(itemIndex));
			for (vint i = 0; i < subColumnCount; i++)
			{
				subItemTexts[i]->SetText(view->GetSubItem(itemIndex, i));
			}

			if (auto controlTemplate = dynamic_cast<templates::GuiListViewTemplate*>(listControl->TypedControlTemplateObject(true)))
			{
				text->SetColor(controlTemplate->GetPrimaryTextColor());
				for (vint i = 0; i < subColumnCount; i++)
				{
					subItemTexts[i]->SetColor(controlTemplate->GetSecondaryTextColor());
				}
			}
		}
		UpdateSubItemSize();
	}

	void DetailListViewItemTemplate::OnFontChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		text->SetFont(GetFont());
		for (auto subText : subItemTexts)
		{
			subText->SetFont(GetFont());
		}
	}

	DetailListViewItemTemplate::DetailListViewItemTemplate()
	{
	}

	DetailListViewItemTemplate::~DetailListViewItemTemplate()
	{
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\ITEMTEMPLATE_ITEXTITEMVIEW.CPP
***********************************************************************/

namespace vl::presentation::controls::list
{
	using namespace collections;
	using namespace elements;
	using namespace compositions;
	using namespace reflection::description;

/***********************************************************************
DefaultTextListItemTemplate
***********************************************************************/

	TemplateProperty<DefaultTextListItemTemplate::BulletStyle> DefaultTextListItemTemplate::CreateBulletStyle()
	{
		return {};
	}

	void DefaultTextListItemTemplate::OnInitialize()
	{
		SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

		textElement = GuiSolidLabelElement::Create();
		textElement->SetAlignments(Alignment::Left, Alignment::Center);

		GuiBoundsComposition* textComposition = new GuiBoundsComposition;
		textComposition->SetOwnedElement(Ptr(textElement));
		textComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElement);

		if (auto bulletStyleController = CreateBulletStyle())
		{
			bulletButton = new GuiSelectableButton(theme::ThemeName::Unknown);
			bulletButton->SetAutoFocus(false);
			bulletButton->SetControlTemplate(bulletStyleController);
			bulletButton->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
			bulletButton->SelectedChanged.AttachMethod(this, &DefaultTextListItemTemplate::OnBulletSelectedChanged);

			GuiTableComposition* table = new GuiTableComposition;
			AddChild(table);
			table->SetAlignmentToParent(Margin(0, 0, 0, 0));
			table->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
			table->SetRowsAndColumns(1, 2);
			table->SetRowOption(0, GuiCellOption::PercentageOption(1.0));
			table->SetColumnOption(0, GuiCellOption::MinSizeOption());
			table->SetColumnOption(1, GuiCellOption::PercentageOption(1.0));
			{
				GuiCellComposition* cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(0, 0, 1, 1);
				cell->AddChild(bulletButton->GetBoundsComposition());
			}
			{
				GuiCellComposition* cell = new GuiCellComposition;
				table->AddChild(cell);
				cell->SetSite(0, 1, 1, 1);
				cell->AddChild(textComposition);
				textComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
			}
		}
		else
		{
			AddChild(textComposition);
			textComposition->SetAlignmentToParent(Margin(5, 2, 0, 2));
		}

		FontChanged.AttachMethod(this, &DefaultTextListItemTemplate::OnFontChanged);
		TextChanged.AttachMethod(this, &DefaultTextListItemTemplate::OnTextChanged);
		TextColorChanged.AttachMethod(this, &DefaultTextListItemTemplate::OnTextColorChanged);
		CheckedChanged.AttachMethod(this, &DefaultTextListItemTemplate::OnCheckedChanged);

		FontChanged.Execute(compositions::GuiEventArgs(this));
		TextChanged.Execute(compositions::GuiEventArgs(this));
		TextColorChanged.Execute(compositions::GuiEventArgs(this));
		CheckedChanged.Execute(compositions::GuiEventArgs(this));
	}

	void DefaultTextListItemTemplate::OnRefresh()
	{
	}

	void DefaultTextListItemTemplate::OnFontChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		textElement->SetFont(GetFont());
	}

	void DefaultTextListItemTemplate::OnTextChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		textElement->SetText(GetText());
	}

	void DefaultTextListItemTemplate::OnTextColorChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		textElement->SetColor(GetTextColor());
	}

	void DefaultTextListItemTemplate::OnCheckedChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		if (bulletButton)
		{
			supressEdit = true;
			bulletButton->SetSelected(GetChecked());
			supressEdit = false;
		}
	}

	void DefaultTextListItemTemplate::OnBulletSelectedChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::list::DefaultTextListItemTemplate::OnBulletSelectedChanged(GuiGraphicsComposition*, GuiEventArgs&)#"
		if (!supressEdit)
		{
			if (auto textItemView = dynamic_cast<ITextItemView*>(listControl->GetItemProvider()->RequestView(WString::Unmanaged(ITextItemView::Identifier))))
			{
				listControl->GetItemProvider()->PushEditing();
				textItemView->SetChecked(GetIndex(), bulletButton->GetSelected());
				CHECK_ERROR(listControl->GetItemProvider()->PopEditing(), ERROR_MESSAGE_PREFIX L"BeginEditListItem and EndEditListItem calls are not paired.");
			}
		}
#undef ERROR_MESSAGE_PREFIX
	}

	DefaultTextListItemTemplate::DefaultTextListItemTemplate()
	{
	}

	DefaultTextListItemTemplate::~DefaultTextListItemTemplate()
	{
	}

/***********************************************************************
DefaultCheckTextListItemTemplate
***********************************************************************/

	TemplateProperty<DefaultTextListItemTemplate::BulletStyle> DefaultCheckTextListItemTemplate::CreateBulletStyle()
	{
		if (auto controlTemplate = dynamic_cast<templates::GuiTextListTemplate*>(listControl->TypedControlTemplateObject(true)))
		{
			auto style = controlTemplate->GetCheckBulletTemplate();
			if (style) return style;
		}
		return theme::GetCurrentTheme()->CreateStyle(theme::ThemeName::CheckTextListItem);
	}

/***********************************************************************
DefaultRadioTextListItemTemplate
***********************************************************************/

	TemplateProperty<DefaultTextListItemTemplate::BulletStyle> DefaultRadioTextListItemTemplate::CreateBulletStyle()
	{
		if (auto controlTemplate = dynamic_cast<templates::GuiTextListTemplate*>(listControl->TypedControlTemplateObject(true)))
		{
			auto style = controlTemplate->GetRadioBulletTemplate();
			if (style) return style;
		}
		return theme::GetCurrentTheme()->CreateStyle(theme::ThemeName::RadioTextListItem);
	}
}

/***********************************************************************
.\CONTROLS\LISTCONTROLPACKAGE\ITEMTEMPLATE_ITREEVIEWITEMVIEW.CPP
***********************************************************************/

namespace vl::presentation::controls::tree
{
	using namespace elements;
	using namespace compositions;
	using namespace reflection::description;

/***********************************************************************
DefaultTreeItemTemplate
***********************************************************************/

	void DefaultTreeItemTemplate::OnInitialize()
	{
		SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

		table = new GuiTableComposition;
		AddChild(table);
		table->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
		table->SetRowsAndColumns(3, 4);
		table->SetRowOption(0, GuiCellOption::PercentageOption(0.5));
		table->SetRowOption(1, GuiCellOption::MinSizeOption());
		table->SetRowOption(2, GuiCellOption::PercentageOption(0.5));
		table->SetColumnOption(0, GuiCellOption::AbsoluteOption(0));
		table->SetColumnOption(1, GuiCellOption::MinSizeOption());
		table->SetColumnOption(2, GuiCellOption::MinSizeOption());
		table->SetColumnOption(3, GuiCellOption::MinSizeOption());
		table->SetAlignmentToParent(Margin(0, 0, 0, 0));
		table->SetCellPadding(2);
		{
			GuiCellComposition* cell = new GuiCellComposition;
			table->AddChild(cell);
			cell->SetSite(0, 1, 3, 1);
			cell->SetPreferredMinSize(Size(16, 16));

			expandingButton = new GuiSelectableButton(theme::ThemeName::TreeItemExpander);
			if (auto controlTemplate = dynamic_cast<templates::GuiTreeViewTemplate*>(listControl->TypedControlTemplateObject(true)))
			{
				if (auto expanderStyle = controlTemplate->GetExpandingDecoratorTemplate())
				{
					expandingButton->SetControlTemplate(expanderStyle);
				}
			}
			expandingButton->SetAutoFocus(false);
			expandingButton->SetAutoSelection(false);
			expandingButton->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
			expandingButton->GetBoundsComposition()->GetEventReceiver()->leftButtonDoubleClick.AttachMethod(this, &DefaultTreeItemTemplate::OnExpandingButtonDoubleClick);
			expandingButton->Clicked.AttachMethod(this, &DefaultTreeItemTemplate::OnExpandingButtonClicked);
			cell->AddChild(expandingButton->GetBoundsComposition());
		}
		{
			GuiCellComposition* cell = new GuiCellComposition;
			table->AddChild(cell);
			cell->SetSite(1, 2, 1, 1);
			cell->SetPreferredMinSize(Size(16, 16));

			imageElement = GuiImageFrameElement::Create();
			imageElement->SetStretch(true);
			cell->SetOwnedElement(Ptr(imageElement));
		}
		{
			GuiCellComposition* cell = new GuiCellComposition;
			table->AddChild(cell);
			cell->SetSite(0, 3, 3, 1);
			cell->SetPreferredMinSize(Size(192, 0));

			textElement = GuiSolidLabelElement::Create();
			textElement->SetAlignments(Alignment::Left, Alignment::Center);
			textElement->SetEllipse(true);
			cell->SetOwnedElement(Ptr(textElement));
		}

		FontChanged.AttachMethod(this, &DefaultTreeItemTemplate::OnFontChanged);
		TextChanged.AttachMethod(this, &DefaultTreeItemTemplate::OnTextChanged);
		TextColorChanged.AttachMethod(this, &DefaultTreeItemTemplate::OnTextColorChanged);
		ExpandingChanged.AttachMethod(this, &DefaultTreeItemTemplate::OnExpandingChanged);
		ExpandableChanged.AttachMethod(this, &DefaultTreeItemTemplate::OnExpandableChanged);
		LevelChanged.AttachMethod(this, &DefaultTreeItemTemplate::OnLevelChanged);
		ImageChanged.AttachMethod(this, &DefaultTreeItemTemplate::OnImageChanged);

		FontChanged.Execute(compositions::GuiEventArgs(this));
		TextChanged.Execute(compositions::GuiEventArgs(this));
		TextColorChanged.Execute(compositions::GuiEventArgs(this));
		ExpandingChanged.Execute(compositions::GuiEventArgs(this));
		ExpandableChanged.Execute(compositions::GuiEventArgs(this));
		LevelChanged.Execute(compositions::GuiEventArgs(this));
		ImageChanged.Execute(compositions::GuiEventArgs(this));
	}

	void DefaultTreeItemTemplate::OnRefresh()
	{
	}

	void DefaultTreeItemTemplate::OnFontChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		textElement->SetFont(GetFont());
	}

	void DefaultTreeItemTemplate::OnTextChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		textElement->SetText(GetText());
	}

	void DefaultTreeItemTemplate::OnTextColorChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		textElement->SetColor(GetTextColor());
	}

	void DefaultTreeItemTemplate::OnExpandingChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		expandingButton->SetSelected(GetExpanding());
	}

	void DefaultTreeItemTemplate::OnExpandableChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		expandingButton->SetVisible(GetExpandable());
	}

	void DefaultTreeItemTemplate::OnLevelChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		table->SetColumnOption(0, GuiCellOption::AbsoluteOption(GetLevel() * 12));
	}

	void DefaultTreeItemTemplate::OnImageChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		if (auto imageData = GetImage())
		{
			imageElement->SetImage(imageData->GetImage(), imageData->GetFrameIndex());
		}
		else
		{
			imageElement->SetImage(nullptr);
		}
	}

	void DefaultTreeItemTemplate::OnExpandingButtonDoubleClick(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
	{
		arguments.handled = true;
	}

	void DefaultTreeItemTemplate::OnExpandingButtonClicked(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
	{
		if (expandingButton->GetVisuallyEnabled())
		{
			if (auto view = dynamic_cast<INodeItemView*>(listControl->GetItemProvider()->RequestView(WString::Unmanaged(INodeItemView::Identifier))))
			{
				vint index = listControl->GetArranger()->GetVisibleIndex(this);
				if (index != -1)
				{
					if (auto node = view->RequestNode(index))
					{
						bool expanding = node->GetExpanding();
						node->SetExpanding(!expanding);
					}
				}
			}
		}
	}

	DefaultTreeItemTemplate::DefaultTreeItemTemplate()
	{
	}

	DefaultTreeItemTemplate::~DefaultTreeItemTemplate()
	{
	}
}

/***********************************************************************
.\CONTROLS\TEMPLATES\GUIANIMATION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace collections;
			using namespace reflection::description;

/***********************************************************************
GuiTimedAnimation
***********************************************************************/

			class GuiTimedAnimation : public Object, public virtual IGuiAnimation
			{
			protected:
				DateTime						startUtcTime;
				vuint64_t						time;
				bool							running = false;

			public:
				GuiTimedAnimation()
				{
				}

				~GuiTimedAnimation()
				{
				}

				void Start()override
				{
					startUtcTime = DateTime::UtcTime();
					time = 0;
					running = true;
				}

				void Pause()override
				{
					time = GetTime();
					running = false;
				}

				void Resume()override
				{
					startUtcTime = DateTime::UtcTime();
					running = true;
				}

				vuint64_t GetTime()
				{
					if (running)
					{
						return time + (DateTime::UtcTime().osMilliseconds - startUtcTime.osMilliseconds);
					}
					else
					{
						return time;
					}
				}
			};

/***********************************************************************
GuiFiniteAnimation
***********************************************************************/

			class GuiFiniteAnimation : public GuiTimedAnimation
			{
			protected:
				vuint64_t						length = 0;
				vuint64_t						currentTime = 0;
				Func<void(vuint64_t)>			run;

			public:
				GuiFiniteAnimation(const Func<void(vuint64_t)>& _run, vuint64_t _length)
					:run(_run)
					, length(_length)
				{
				}

				~GuiFiniteAnimation()
				{
				}

				void Run()override
				{
					currentTime = GetTime();
					if (currentTime < length && run)
					{
						run(currentTime);
					}
				}

				bool GetStopped()override
				{
					return currentTime >= length;
				}
			};

/***********************************************************************
GuiInfiniteAnimation
***********************************************************************/

			class GuiInfiniteAnimation : public GuiTimedAnimation
			{
			protected:
				Func<void(vuint64_t)>			run;

			public:
				GuiInfiniteAnimation(const Func<void(vuint64_t)>& _run)
					:run(_run)
				{
				}

				~GuiInfiniteAnimation()
				{
				}

				void Run()override
				{
					if (run)
					{
						run(GetTime());
					}
				}

				bool GetStopped()override
				{
					return false;
				}
			};

/***********************************************************************
IGuiAnimation
***********************************************************************/

			Ptr<IGuiAnimation> IGuiAnimation::CreateAnimation(const Func<void(vuint64_t)>& run, vuint64_t milliseconds)
			{
				return Ptr(new GuiFiniteAnimation(run, milliseconds));
			}

			Ptr<IGuiAnimation> IGuiAnimation::CreateAnimation(const Func<void(vuint64_t)>& run)
			{
				return Ptr(new GuiInfiniteAnimation(run));
			}

/***********************************************************************
IGuiAnimationCoroutine
***********************************************************************/

			class GuiCoroutineAnimation : public Object, public virtual IGuiAnimationCoroutine::IImpl
			{
			protected:
				IGuiAnimationCoroutine::Creator				creator;
				Ptr<ICoroutine>								coroutine;

				Ptr<IGuiAnimation>							waitingAnimation;
				vint										waitingGroup = -1;
				Group<vint, Ptr<IGuiAnimation>>				groupAnimations;

			public:
				GuiCoroutineAnimation(const IGuiAnimationCoroutine::Creator& _creator)
					:creator(_creator)
				{
				}

				~GuiCoroutineAnimation()
				{
				}

				void OnPlayAndWait(Ptr<IGuiAnimation> animation)override
				{
					CHECK_ERROR(!waitingAnimation && waitingGroup == -1, L"GuiCoroutineAnimation::OnPlayAndWait(Ptr<IGuiAnimation>)#Cannot be called when an animation or a group has already been waiting for.");
					waitingAnimation = animation;
					waitingAnimation->Start();
				}

				void OnPlayInGroup(Ptr<IGuiAnimation> animation, vint groupId)override
				{
					groupAnimations.Add(groupId, animation);
					animation->Start();
				}

				void OnWaitForGroup(vint groupId)override
				{
					CHECK_ERROR(!waitingAnimation && waitingGroup == -1, L"GuiCoroutineAnimation::OnWaitForGroup(vint)#Cannot be called when an animation or a group has already been waiting for.");
					if (groupAnimations.Keys().Contains(groupId))
					{
						waitingGroup = groupId;
					}
				}

				void Start()override
				{
					CHECK_ERROR(!coroutine, L"GuiCoroutineAnimation::Start()#Cannot be called more than once.");
					coroutine = creator(this);
				}

				void Pause()override
				{
					if (waitingAnimation)
					{
						waitingAnimation->Pause();
					}
					// TODO: (enumerable) foreach on group
					for (vint i = 0; i < groupAnimations.Count(); i++)
					{
						for (auto animation : groupAnimations.GetByIndex(i))
						{
							animation->Pause();
						}
					}
				}

				void Resume()override
				{
					if (waitingAnimation)
					{
						waitingAnimation->Resume();
					}
					// TODO: (enumerable) foreach on group
					for (vint i = 0; i < groupAnimations.Count(); i++)
					{
						for (auto animation : groupAnimations.GetByIndex(i))
						{
							animation->Resume();
						}
					}
				}

				void Run()override
				{
					CHECK_ERROR(coroutine, L"GuiCoroutineAnimation::Run()#Cannot be called before calling Start.");

					if (waitingAnimation)
					{
						waitingAnimation->Run();
						if (waitingAnimation->GetStopped())
						{
							waitingAnimation = nullptr;
						}
					}

					// TODO: (enumerable) foreach:reversed on group
					for (vint i = groupAnimations.Count() - 1; i >= 0; i--)
					{
						auto& animations = groupAnimations.GetByIndex(i);
						for (vint j = animations.Count() - 1; j >= 0; j--)
						{
							auto animation = animations[j];
							animation->Run();
							if (animation->GetStopped())
							{
								groupAnimations.Remove(i, animation.Obj());
							}
						}
					}

					if (waitingGroup != -1 && !groupAnimations.Keys().Contains(waitingGroup))
					{
						waitingGroup = -1;
					}

					if (coroutine->GetStatus() == CoroutineStatus::Waiting)
					{
						if (waitingAnimation || waitingGroup != -1)
						{
							return;
						}
						coroutine->Resume(true, nullptr);
					}
				}

				bool GetStopped()override
				{
					if (!coroutine) return false;
					if (coroutine->GetStatus() != CoroutineStatus::Stopped) return false;
					if (waitingAnimation || groupAnimations.Count() > 0) return false;
					return true;
				}
			};

			void IGuiAnimationCoroutine::WaitAndPause(IImpl* impl, vuint64_t milliseconds)
			{
				return PlayAndWaitAndPause(impl, IGuiAnimation::CreateAnimation({}, milliseconds));
			}

			void IGuiAnimationCoroutine::PlayAndWaitAndPause(IImpl* impl, Ptr<IGuiAnimation> animation)
			{
				impl->OnPlayAndWait(animation);
			}

			void IGuiAnimationCoroutine::PlayInGroupAndPause(IImpl* impl, Ptr<IGuiAnimation> animation, vint groupId)
			{
				impl->OnPlayInGroup(animation, groupId);
			}

			void IGuiAnimationCoroutine::WaitForGroupAndPause(IImpl* impl, vint groupId)
			{
				impl->OnWaitForGroup(groupId);
			}

			void IGuiAnimationCoroutine::ReturnAndExit(IImpl* impl)
			{
			}

			Ptr<IGuiAnimation> IGuiAnimationCoroutine::Create(const Creator& creator)
			{
				return Ptr(new GuiCoroutineAnimation(creator));
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\TEMPLATES\GUICOMMONTEMPLATES.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace templates
		{
			using namespace elements;
			using namespace compositions;
			using namespace templates;
			using namespace controls;
			using namespace theme;

/***********************************************************************
GuiCommonDatePickerLook
***********************************************************************/

			vint GetDayCountForMonth(vint year, vint month)
			{
				bool isLeapYear = (year % 100 == 0) ? (year % 400 == 0) : (year % 4 == 0);
				switch (month)
				{
				case 1:case 3:case 5:case 7:case 8:case 10:case 12:
					return 31;
				case 4:case 6:case 9:case 11:
					return 30;
				default:
					return isLeapYear ? 29 : 28;
				}
			}

			void StepPreviousMonth(vint& year, vint& month)
			{
				if (month == 1)
				{
					year--;
					month = 12;
				}
				else
				{
					month--;
				}
			}

			void StepNextMonth(vint& year, vint& month)
			{
				if (month == 12)
				{
					year++;
					month = 1;
				}
				else
				{
					month++;
				}
			}

			void GuiCommonDatePickerLook::SetDay(const DateTime& day, vint& index, vint monthOffset)
			{
				dateDays[index] = day;
				GuiSolidLabelElement* label = labelDays[index];
				label->SetText(itow(day.day));
				label->SetColor(monthOffset == 0 ? primaryTextColor : secondaryTextColor);

				wchar_t alt[] = L"D00";
				if (monthOffset == -1) alt[0] = L'C';
				else if (monthOffset == 1) alt[0] = L'E';
				alt[1] = (wchar_t)(L'0' + day.day / 10);
				alt[2] = (wchar_t)(L'0' + day.day % 10);
				buttonDays[index]->SetAlt(alt);

				index++;
			}

			void GuiCommonDatePickerLook::comboYearMonth_SelectedIndexChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (!preventComboEvent)
				{
					if (comboYear->GetSelectedIndex() != -1 && comboMonth->GetSelectedIndex() != -1)
					{
						vint year = comboYear->GetSelectedIndex() + YearFirst;
						vint month = comboMonth->GetSelectedIndex() + 1;
						SetDate(DateTime::FromDateTime(year, month, 1));

						GuiEventArgs arguments(this);
						DateChanged.Execute(arguments);
						commands->NotifyDateChanged();
						commands->NotifyDateNavigated();
					}
				}
			}

			void GuiCommonDatePickerLook::buttonDay_SelectedChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (!preventButtonEvent)
				{
					GuiSelectableButton* button = dynamic_cast<GuiSelectableButton*>(sender->GetRelatedControl());
					if (button->GetSelected())
					{
						vint index = buttonDays.IndexOf(button);
						if (index != -1)
						{
							DateTime day = dateDays[index];
							if (day.year != currentDate.year || day.month != currentDate.month)
							{
								SetDate(day);
							}
							else
							{
								currentDate = day;
							}

							GuiEventArgs arguments(this);
							DateChanged.Execute(arguments);
							commands->NotifyDateChanged();
							commands->NotifyDateSelected();
						}
					}
				}
			}

			void GuiCommonDatePickerLook::DisplayMonth(vint year, vint month)
			{
				if (YearFirst <= year && year <= YearLast && 1 <= month && month <= 12)
				{
					preventComboEvent = true;
					comboYear->SetSelectedIndex(year - YearFirst);
					comboMonth->SetSelectedIndex(month - 1);
					preventComboEvent = false;
				}

				vint yearPrev = year, yearNext = year, monthPrev = month, monthNext = month;
				StepPreviousMonth(yearPrev, monthPrev);
				StepNextMonth(yearNext, monthNext);

				vint countPrev = GetDayCountForMonth(yearPrev, monthPrev);
				vint count = GetDayCountForMonth(year, month);
				vint countNext = GetDayCountForMonth(yearNext, monthNext);

				DateTime firstDay = DateTime::FromDateTime(year, month, 1);
				vint showPrev = firstDay.dayOfWeek;
				if (showPrev == 0) showPrev = DaysOfWeek;
				vint show = count;
				vint showNext = DaysOfWeek*DayRows - showPrev - show;

				vint index = 0;
				for (vint i = 0; i < showPrev; i++)
				{
					DateTime day = DateTime::FromDateTime(yearPrev, monthPrev, countPrev - (showPrev - i - 1));
					SetDay(day, index, -1);
				}
				for (vint i = 0; i < show; i++)
				{
					DateTime day = DateTime::FromDateTime(year, month, i + 1);
					SetDay(day, index, 0);
				}
				for (vint i = 0; i < showNext; i++)
				{
					DateTime day = DateTime::FromDateTime(yearNext, monthNext, i + 1);
					SetDay(day, index, 1);
				}
			}

			void GuiCommonDatePickerLook::SelectDay(vint day)
			{
				// TODO: (enumerable) foreach:indexed
				for (vint i = 0; i < dateDays.Count(); i++)
				{
					const DateTime& dt = dateDays[i];
					if (dt.year == currentDate.year && dt.month == currentDate.month && dt.day == day)
					{
						preventButtonEvent = true;
						buttonDays[i]->SetSelected(true);
						preventButtonEvent = false;
						break;
					}
				}
			}

			GuiCommonDatePickerLook::GuiCommonDatePickerLook(Color _backgroundColor, Color _primaryTextColor, Color _secondaryTextColor)
				:backgroundColor(_backgroundColor)
				, primaryTextColor(_primaryTextColor)
				, secondaryTextColor(_secondaryTextColor)
			{
				DateChanged.SetAssociatedComposition(this);
				SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

				GuiTableComposition* monthTable = 0;
				GuiTableComposition* dayTable = 0;
				{
					listYears = new GuiTextList(theme::ThemeName::TextList);
					listYears->SetHorizontalAlwaysVisible(false);
					for (vint i = YearFirst; i <= YearLast; i++)
					{
						listYears->GetItems().Add(Ptr(new list::TextItem(itow(i))));
					}
					comboYear = new GuiComboBoxListControl(theme::ThemeName::ComboBox, listYears);
					comboYear->SetAlt(L"Y");
					comboYear->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 2, 0));
					comboYear->SelectedIndexChanged.AttachMethod(this, &GuiCommonDatePickerLook::comboYearMonth_SelectedIndexChanged);
				}
				{
					listMonths = new GuiTextList(theme::ThemeName::TextList);
					listMonths->SetHorizontalAlwaysVisible(false);
					comboMonth = new GuiComboBoxListControl(theme::ThemeName::ComboBox, listMonths);
					comboMonth->SetAlt(L"M");
					comboMonth->GetBoundsComposition()->SetAlignmentToParent(Margin(2, 0, 0, 0));
					comboMonth->SelectedIndexChanged.AttachMethod(this, &GuiCommonDatePickerLook::comboYearMonth_SelectedIndexChanged);
				}
				{
					monthTable = new GuiTableComposition;
					monthTable->SetAlignmentToParent(Margin(0, 0, 0, 0));
					monthTable->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					monthTable->SetRowsAndColumns(1, 2);
					monthTable->SetRowOption(0, GuiCellOption::MinSizeOption());
					monthTable->SetColumnOption(0, GuiCellOption::PercentageOption(0.5));
					monthTable->SetColumnOption(1, GuiCellOption::PercentageOption(0.5));
					{
						GuiCellComposition* cell = new GuiCellComposition;
						monthTable->AddChild(cell);
						cell->SetSite(0, 0, 1, 1);
						cell->AddChild(comboYear->GetBoundsComposition());
					}
					{
						GuiCellComposition* cell = new GuiCellComposition;
						monthTable->AddChild(cell);
						cell->SetSite(0, 1, 1, 1);
						cell->AddChild(comboMonth->GetBoundsComposition());
					}
				}
				{
					dayTable = new GuiTableComposition;
					dayTable->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					dayTable->SetCellPadding(4);
					dayTable->SetRowsAndColumns(DayRows + DayRowStart, DaysOfWeek);

					for (vint i = 0; i < DayRowStart; i++)
					{
						dayTable->SetRowOption(i, GuiCellOption::MinSizeOption());
					}
					for (vint i = 0; i < DayRows; i++)
					{
						dayTable->SetRowOption(i + DayRowStart, GuiCellOption::PercentageOption(1.0));
					}
					for (vint i = 0; i < DaysOfWeek; i++)
					{
						dayTable->SetColumnOption(i, GuiCellOption::PercentageOption(1.0));
					}

					{
						GuiCellComposition* cell = new GuiCellComposition;
						dayTable->AddChild(cell);
						cell->SetSite(0, 0, 1, DaysOfWeek);
						cell->AddChild(monthTable);
					}

					labelDaysOfWeek.Resize(7);
					for (vint i = 0; i < DaysOfWeek; i++)
					{
						GuiCellComposition* cell = new GuiCellComposition;
						dayTable->AddChild(cell);
						cell->SetSite(1, i, 1, 1);

						auto element = Ptr(GuiSolidLabelElement::Create());
						element->SetAlignments(Alignment::Center, Alignment::Center);
						element->SetColor(primaryTextColor);
						labelDaysOfWeek[i] = element.Obj();
						cell->SetOwnedElement(element);
					}

					buttonDays.Resize(DaysOfWeek*DayRows);
					labelDays.Resize(DaysOfWeek*DayRows);
					dateDays.Resize(DaysOfWeek*DayRows);

					auto dayMutexController = new GuiSelectableButton::MutexGroupController;
					AddComponent(dayMutexController);

					for (vint j = 0; j < DayRows; j++)
					{
						for (vint i = 0; i < DaysOfWeek; i++)
						{
							GuiCellComposition* cell = new GuiCellComposition;
							dayTable->AddChild(cell);
							cell->SetSite(j + DayRowStart, i, 1, 1);

							GuiSelectableButton* button = new GuiSelectableButton(theme::ThemeName::CheckBox);
							button->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
							button->SetGroupController(dayMutexController);
							button->SelectedChanged.AttachMethod(this, &GuiCommonDatePickerLook::buttonDay_SelectedChanged);
							cell->AddChild(button->GetBoundsComposition());
							buttonDays[j*DaysOfWeek + i] = button;

							auto element = Ptr(GuiSolidLabelElement::Create());
							element->SetAlignments(Alignment::Center, Alignment::Center);
							element->SetText(L"0");
							labelDays[j*DaysOfWeek + i] = element.Obj();

							GuiBoundsComposition* elementBounds = new GuiBoundsComposition;
							elementBounds->SetOwnedElement(element);
							elementBounds->SetAlignmentToParent(Margin(0, 0, 0, 0));
							elementBounds->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElement);
							button->GetContainerComposition()->AddChild(elementBounds);
						}
					}
				}
				{
					auto element = Ptr(GuiSolidBackgroundElement::Create());
					element->SetColor(backgroundColor);
					dayTable->SetOwnedElement(element);
				}

				dayTable->SetAlignmentToParent(Margin(0, 0, 0, 0));
				AddChild(dayTable);

				SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				SetFont(font);
			}

			GuiCommonDatePickerLook::~GuiCommonDatePickerLook()
			{
				FinalizeInstanceRecursively(this);
			}

			controls::IDatePickerCommandExecutor* GuiCommonDatePickerLook::GetCommands()
			{
				return commands;
			}

			void GuiCommonDatePickerLook::SetCommands(controls::IDatePickerCommandExecutor* value)
			{
				commands = value;
			}

			TemplateProperty<GuiSelectableButtonTemplate> GuiCommonDatePickerLook::GetDateButtonTemplate()
			{
				return dateButtonTemplate;
			}

			void GuiCommonDatePickerLook::SetDateButtonTemplate(const TemplateProperty<GuiSelectableButtonTemplate>& value)
			{
				dateButtonTemplate = value;
				for (auto button : buttonDays)
				{
					button->SetControlTemplate(value);
				}
			}

			TemplateProperty<GuiTextListTemplate> GuiCommonDatePickerLook::GetDateTextListTemplate()
			{
				return dateTextListTemplate;
			}

			void GuiCommonDatePickerLook::SetDateTextListTemplate(const TemplateProperty<GuiTextListTemplate>& value)
			{
				dateTextListTemplate = value;
				listYears->SetControlTemplate(value);
				listMonths->SetControlTemplate(value);
			}

			TemplateProperty<GuiComboBoxTemplate> GuiCommonDatePickerLook::GetDateComboBoxTemplate()
			{
				return dateComboBoxTemplate;
			}

			void GuiCommonDatePickerLook::SetDateComboBoxTemplate(const TemplateProperty<GuiComboBoxTemplate>& value)
			{
				dateComboBoxTemplate = value;
				comboYear->SetControlTemplate(value);
				comboMonth->SetControlTemplate(value);
			}

			const Locale& GuiCommonDatePickerLook::GetDateLocale()
			{
				return dateLocale;
			}

			void GuiCommonDatePickerLook::SetDateLocale(const Locale& value)
			{
				if (dateLocale != value)
				{
					dateLocale = value;
					for (vint i = 0; i < DaysOfWeek; i++)
					{
						labelDaysOfWeek[i]->SetText(dateLocale.GetShortDayOfWeekName(i));
					}

					listMonths->GetItems().Clear();
					for (vint i = 1; i <= 12; i++)
					{
						listMonths->GetItems().Add(Ptr(new list::TextItem(dateLocale.GetLongMonthName(i))));
					}

					SetDate(currentDate);
				}
			}

			const DateTime& GuiCommonDatePickerLook::GetDate()
			{
				return currentDate;
			}

			void GuiCommonDatePickerLook::SetDate(const DateTime& value)
			{
				currentDate = value;
				DisplayMonth(value.year, value.month);
				SelectDay(value.day);
			}

			const FontProperties& GuiCommonDatePickerLook::GetFont()
			{
				return font;
			}

			void GuiCommonDatePickerLook::SetFont(const FontProperties& value)
			{
				if (font != value)
				{
					font = value;
					comboYear->SetFont(value);
					listYears->SetFont(value);
					comboMonth->SetFont(value);
					listMonths->SetFont(value);
					for (auto label : From(labelDaysOfWeek).Concat(labelDays))
					{
						label->SetFont(value);
					}
				}
			}

			controls::GuiComboBoxListControl* GuiCommonDatePickerLook::GetYearCombo()
			{
				return comboYear;
			}

			controls::GuiComboBoxListControl* GuiCommonDatePickerLook::GetMonthCombo()
			{
				return comboMonth;
			}

			vint GuiCommonDatePickerLook::GetDayRows()
			{
				return DaysOfWeek;
			}

			vint GuiCommonDatePickerLook::GetDayColumns()
			{
				return DayRows;
			}

			controls::GuiSelectableButton* GuiCommonDatePickerLook::GetDayButton(vint row, vint column)
			{
				return buttonDays[row * DaysOfWeek + column];
			}

			DateTime GuiCommonDatePickerLook::GetDateOfDayButton(vint row, vint column)
			{
				return dateDays[row * DaysOfWeek + column];
			}

/***********************************************************************
GuiCommonScrollViewLook
***********************************************************************/

			void GuiCommonScrollViewLook::UpdateTable()
			{
				if (horizontalScroll->GetVisible())
				{
					tableComposition->SetRowOption(1, GuiCellOption::AbsoluteOption(defaultScrollSize));
				}
				else
				{
					tableComposition->SetRowOption(1, GuiCellOption::AbsoluteOption(0));
				}

				if (verticalScroll->GetVisible())
				{
					tableComposition->SetColumnOption(1, GuiCellOption::AbsoluteOption(defaultScrollSize));
				}
				else
				{
					tableComposition->SetColumnOption(1, GuiCellOption::AbsoluteOption(0));
				}
			}

			void GuiCommonScrollViewLook::hScroll_OnVisibleChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				UpdateTable();
			}

			void GuiCommonScrollViewLook::vScroll_OnVisibleChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				UpdateTable();
			}

			GuiCommonScrollViewLook::GuiCommonScrollViewLook(vint _defaultScrollSize)
				:defaultScrollSize(_defaultScrollSize)
			{
				SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

				horizontalScroll = new GuiScroll(theme::ThemeName::HScroll);
				horizontalScroll->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
				horizontalScroll->SetEnabled(false);
				horizontalScroll->SetAutoFocus(false);
				verticalScroll = new GuiScroll(theme::ThemeName::VScroll);
				verticalScroll->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
				verticalScroll->SetEnabled(false);
				verticalScroll->SetAutoFocus(false);

				tableComposition = new GuiTableComposition;
				AddChild(tableComposition);
				tableComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				tableComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				tableComposition->SetRowsAndColumns(2, 2);
				tableComposition->SetRowOption(0, GuiCellOption::PercentageOption(1.0));
				tableComposition->SetRowOption(1, GuiCellOption::MinSizeOption());
				tableComposition->SetColumnOption(0, GuiCellOption::PercentageOption(1.0));
				tableComposition->SetColumnOption(1, GuiCellOption::MinSizeOption());
				UpdateTable();
				{
					GuiCellComposition* cell = new GuiCellComposition;
					tableComposition->AddChild(cell);
					cell->SetSite(1, 0, 1, 1);
					cell->AddChild(horizontalScroll->GetBoundsComposition());
				}
				{
					GuiCellComposition* cell = new GuiCellComposition;
					tableComposition->AddChild(cell);
					cell->SetSite(0, 1, 1, 1);
					cell->AddChild(verticalScroll->GetBoundsComposition());
				}

				containerCellComposition = new GuiCellComposition;
				tableComposition->AddChild(containerCellComposition);
				containerCellComposition->SetSite(0, 0, 1, 1);

				containerComposition = new GuiBoundsComposition;
				containerComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				containerCellComposition->AddChild(containerComposition);

				horizontalScroll->VisibleChanged.AttachMethod(this, &GuiCommonScrollViewLook::hScroll_OnVisibleChanged);
				verticalScroll->VisibleChanged.AttachMethod(this, &GuiCommonScrollViewLook::vScroll_OnVisibleChanged);
				UpdateTable();
			}

			GuiCommonScrollViewLook::~GuiCommonScrollViewLook()
			{
			}

			controls::GuiScroll* GuiCommonScrollViewLook::GetHScroll()
			{
				return horizontalScroll;
			}

			controls::GuiScroll* GuiCommonScrollViewLook::GetVScroll()
			{
				return verticalScroll;
			}

			compositions::GuiGraphicsComposition* GuiCommonScrollViewLook::GetContainerComposition()
			{
				return containerComposition;
			}

			TemplateProperty<GuiScrollTemplate> GuiCommonScrollViewLook::GetHScrollTemplate()
			{
				return hScrollTemplate;
			}

			void GuiCommonScrollViewLook::SetHScrollTemplate(const TemplateProperty<GuiScrollTemplate>& value)
			{
				hScrollTemplate = value;
				horizontalScroll->SetControlTemplate(value);
			}

			TemplateProperty<GuiScrollTemplate> GuiCommonScrollViewLook::GetVScrollTemplate()
			{
				return vScrollTemplate;
			}

			void GuiCommonScrollViewLook::SetVScrollTemplate(const TemplateProperty<GuiScrollTemplate>& value)
			{
				vScrollTemplate = value;
				verticalScroll->SetControlTemplate(value);
			}

/***********************************************************************
GuiCommonScrollBehavior
***********************************************************************/

			void GuiCommonScrollBehavior::SetScroll(vint totalPixels, vint newOffset)
			{
				vint totalSize = scrollTemplate->GetTotalSize();
				double ratio = (double)newOffset / totalPixels;
				vint newPosition = (vint)round(ratio * totalSize);

				vint offset1 = (vint)round(((double)newPosition / totalSize) * totalPixels);
				vint offset2 = (vint)round(((double)(newPosition + 1)) / totalSize * totalPixels);
				vint delta1 = offset1 - newOffset;
				vint delta2 = offset2 - newOffset;

				if (delta1 < 0) { delta1 = -delta1; }
				if (delta2 < 0) { delta2 = -delta2; }

				if (delta1 < delta2)
				{
					scrollTemplate->GetCommands()->SetPosition(newPosition);
				}
				else
				{
					scrollTemplate->GetCommands()->SetPosition(newPosition + 1);
				}
			}

			void GuiCommonScrollBehavior::AttachHandle(compositions::GuiGraphicsComposition* handle)
			{
				handle->GetEventReceiver()->leftButtonDown.AttachLambda([=, this](GuiGraphicsComposition*, GuiMouseEventArgs& arguments)
				{
					if (scrollTemplate->GetVisuallyEnabled())
					{
						dragging = true;
						location.x = arguments.x;
						location.y = arguments.y;
					}
				});

				handle->GetEventReceiver()->leftButtonUp.AttachLambda([=, this](GuiGraphicsComposition*, GuiMouseEventArgs&)
				{
					if (scrollTemplate->GetVisuallyEnabled())
					{
						dragging = false;
					}
				});
			}

			GuiCommonScrollBehavior::GuiCommonScrollBehavior()
			{
			}

			GuiCommonScrollBehavior::~GuiCommonScrollBehavior()
			{
			}

			void GuiCommonScrollBehavior::AttachScrollTemplate(GuiScrollTemplate* value)
			{
				scrollTemplate = value;
			}

			void GuiCommonScrollBehavior::AttachDecreaseButton(controls::GuiButton* button)
			{
				button->Clicked.AttachLambda([=, this](GuiGraphicsComposition*, GuiEventArgs&)
				{
					scrollTemplate->GetCommands()->SmallDecrease();
				});
			}

			void GuiCommonScrollBehavior::AttachIncreaseButton(controls::GuiButton* button)
			{
				button->Clicked.AttachLambda([=, this](GuiGraphicsComposition*, GuiEventArgs&)
				{
					scrollTemplate->GetCommands()->SmallIncrease();
				});
			}

			void GuiCommonScrollBehavior::AttachHorizontalScrollHandle(compositions::GuiPartialViewComposition* partialView)
			{
				partialView->GetParent()->GetEventReceiver()->leftButtonDown.AttachLambda([=, this](GuiGraphicsComposition*, GuiMouseEventArgs& arguments)
				{
					if (scrollTemplate->GetVisuallyEnabled())
					{
						if (arguments.x < partialView->GetCachedBounds().x1)
						{
							scrollTemplate->GetCommands()->BigDecrease();
						}
						else if (arguments.x >= partialView->GetCachedBounds().x2)
						{
							scrollTemplate->GetCommands()->BigIncrease();
						}
					}
				});

				AttachHorizontalTrackerHandle(partialView);
			}

			void GuiCommonScrollBehavior::AttachVerticalScrollHandle(compositions::GuiPartialViewComposition* partialView)
			{
				partialView->GetParent()->GetEventReceiver()->leftButtonDown.AttachLambda([=, this](GuiGraphicsComposition*, GuiMouseEventArgs& arguments)
				{
					if (scrollTemplate->GetVisuallyEnabled())
					{
						if (arguments.y < partialView->GetCachedBounds().y1)
						{
							scrollTemplate->GetCommands()->BigDecrease();
						}
						else if (arguments.y >= partialView->GetCachedBounds().y2)
						{
							scrollTemplate->GetCommands()->BigIncrease();
						}
					}
				});

				AttachVerticalTrackerHandle(partialView);
			}

			void GuiCommonScrollBehavior::AttachHorizontalTrackerHandle(compositions::GuiPartialViewComposition* partialView)
			{
				partialView->GetEventReceiver()->mouseMove.AttachLambda([=, this](GuiGraphicsComposition*, GuiMouseEventArgs& arguments)
				{
					if (dragging)
					{
						auto bounds = partialView->GetParent()->GetCachedBounds();
						vint totalPixels = bounds.x2 - bounds.x1;
						vint currentOffset = partialView->GetCachedBounds().x1;
						vint newOffset = currentOffset + (arguments.x - location.x);
						SetScroll(totalPixels, newOffset);
					}
				});

				AttachHandle(partialView);
			}

			void GuiCommonScrollBehavior::AttachVerticalTrackerHandle(compositions::GuiPartialViewComposition* partialView)
			{
				partialView->GetEventReceiver()->mouseMove.AttachLambda([=, this](GuiGraphicsComposition*, GuiMouseEventArgs& arguments)
				{
					if (dragging)
					{
						auto bounds = partialView->GetParent()->GetCachedBounds();
						vint totalPixels = bounds.y2 - bounds.y1;
						vint currentOffset = partialView->GetCachedBounds().y1;
						vint newOffset = currentOffset + (arguments.y - location.y);
						SetScroll(totalPixels, newOffset);
					}
				});

				AttachHandle(partialView);
			}

			vint GuiCommonScrollBehavior::GetHorizontalTrackerHandlerPosition(compositions::GuiBoundsComposition* handle, vint totalSize, vint pageSize, vint position)
			{
				vint width = handle->GetParent()->GetCachedBounds().Width() - handle->GetCachedBounds().Width();
				vint max = totalSize - pageSize;
				return max == 0 ? 0 : width * position / max;
			}

			vint GuiCommonScrollBehavior::GetVerticalTrackerHandlerPosition(compositions::GuiBoundsComposition* handle, vint totalSize, vint pageSize, vint position)
			{
				vint height = handle->GetParent()->GetCachedBounds().Height() - handle->GetCachedBounds().Height();
				vint max = totalSize - pageSize;
				return max == 0 ? 0 : height * position / max;
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\TEMPLATES\GUICONTROLTEMPLATES.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace templates
		{
			using namespace collections;
			using namespace controls;
			using namespace compositions;
			using namespace elements;

/***********************************************************************
Template Declarations
***********************************************************************/

			GUI_CONTROL_TEMPLATE_DECL(GUI_TEMPLATE_CLASS_IMPL)
			GUI_ITEM_TEMPLATE_DECL(GUI_TEMPLATE_CLASS_IMPL)
		}
	}
}

/***********************************************************************
.\CONTROLS\TEMPLATES\GUITHEMESTYLEFACTORY.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace theme
		{
			using namespace collections;
			using namespace controls;
			using namespace templates;

			class Theme : public Object, public virtual theme::ITheme
			{
			public:
				Dictionary<WString, Ptr<ThemeTemplates>>	templates;
				ThemeTemplates*								first = nullptr;
				ThemeTemplates*								last = nullptr;

				bool RegisterTheme(const WString& name, Ptr<ThemeTemplates> theme)
				{
					CHECK_ERROR(theme->previous == nullptr, L"vl::presentation::theme::RegisterTheme(const WString&, Ptr<ThemeTemplates>)#Theme object has been registered");
					CHECK_ERROR(theme->next == nullptr, L"vl::presentation::theme::RegisterTheme(const WString&, Ptr<ThemeTemplates>)#Theme object has been registered");

					if (templates.Keys().Contains(name))
					{
						return false;
					}
					templates.Add(name, theme);

					if (!first)
					{
						first = theme.Obj();
					}
					if (last)
					{
						last->next = theme.Obj();
					}
					theme->previous = last;
					last = theme.Obj();

					return true;
				}

				Ptr<ThemeTemplates> UnregisterTheme(const WString& name)
				{
					vint index = templates.Keys().IndexOf(name);
					if (index == -1)
					{
						return nullptr;
					}

					auto themeTemplates = templates.Values().Get(index);

					if (themeTemplates->previous)
					{
						themeTemplates->previous->next = themeTemplates->next;
					}
					else
					{
						first = themeTemplates->next;
					}

					if (themeTemplates->next)
					{
						themeTemplates->next->previous = themeTemplates->previous;

					}
					else
					{
						last = themeTemplates->previous;
					}

					templates.Remove(name);
					return themeTemplates;
				}

				TemplateProperty<GuiControlTemplate> CreateStyle(ThemeName themeName)override
				{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::theme::ITheme::CreateStyle(ThemeName)#"
					if (themeName == ThemeName::Window)
					{
						bool preferCustomFrameWindow = true;
						auto current = last;
						while (current)
						{
							if (current->PreferCustomFrameWindow)
							{
								preferCustomFrameWindow = current->PreferCustomFrameWindow.Value();
								break;
							}
							current = current->previous;
						}

						CHECK_ERROR(current, ERROR_MESSAGE_PREFIX L"At least one ThemeTemplates::PreferCustomFrameWindow should be defined.");

						if (preferCustomFrameWindow)
						{
							themeName = ThemeName::CustomFrameWindow;
						}
						else
						{
							themeName = ThemeName::SystemFrameWindow;
						}
					}

					switch (themeName)
					{
#define GUI_DEFINE_ITEM_PROPERTY(TEMPLATE, CONTROL) \
					case ThemeName::CONTROL:\
						{\
							auto current = last;\
							while (current) \
							{\
								if (current->CONTROL)\
								{\
									return current->CONTROL; \
								}\
								current = current->previous;\
							}\
							throw Exception(L"Control template for \"" L ## #CONTROL L"\" is not defined.");\
						}\

						GUI_CONTROL_TEMPLATE_TYPES(GUI_DEFINE_ITEM_PROPERTY)
#undef GUI_DEFINE_ITEM_PROPERTY
					default:
						CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unknown theme name.");
					}
#undef ERROR_MESSAGE_PREFIX
				}
			};

			controls::GuiControlHost* ThemeTemplates::GetControlHostForInstance()
			{
				return nullptr;
			}

			ThemeTemplates::~ThemeTemplates()
			{
				FinalizeAggregation();
			}

			Theme* currentTheme = nullptr;

			ITheme* GetCurrentTheme()
			{
				return currentTheme;
			}

			void InitializeTheme()
			{
				CHECK_ERROR(currentTheme == nullptr, L"vl::presentation::theme::InitializeTheme()#Theme has already been initialized");
				currentTheme = new Theme;
			}

			void FinalizeTheme()
			{
				CHECK_ERROR(currentTheme != nullptr, L"vl::presentation::theme::FinalizeTheme()#Theme has not been initialized");
				delete currentTheme;
				currentTheme = nullptr;
			}

			bool RegisterTheme(Ptr<ThemeTemplates> theme)
			{
				CHECK_ERROR(currentTheme != nullptr, L"vl::presentation::theme::RegisterTheme(const WString&, Ptr<ThemeTemplates>)#Theme has already been initialized");
				return currentTheme->RegisterTheme(theme->Name, theme);
			}

			Ptr<ThemeTemplates> UnregisterTheme(const WString& name)
			{
				CHECK_ERROR(currentTheme != nullptr, L"vl::presentation::theme::UnregisterTheme(const WString&)#Theme has already been initialized");
				return currentTheme->UnregisterTheme(name);
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\TEXTEDITORPACKAGE\GUIDOCUMENTCOMMONINTERFACE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace collections;
			using namespace elements;
			using namespace compositions;

/***********************************************************************
GuiDocumentItem
***********************************************************************/

			GuiDocumentItem::GuiDocumentItem(const WString& _name)
				:name(_name)
			{
				container = new GuiBoundsComposition;
				container->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				container->SetAssociatedCursor(GetCurrentController()->ResourceService()->GetSystemCursor(INativeCursor::Arrow));
			}

			GuiDocumentItem::~GuiDocumentItem()
			{
				if (!owned)
				{
					SafeDeleteComposition(container);
				}
			}

			compositions::GuiGraphicsComposition* GuiDocumentItem::GetContainer()
			{
				return container;
			}

			WString GuiDocumentItem::GetName()
			{
				return name;
			}

/***********************************************************************
GuiDocumentCommonInterface
***********************************************************************/
			
			void GuiDocumentCommonInterface::InvokeUndoRedoChanged()
			{
				UndoRedoChanged.Execute(documentControl->GetNotifyEventArguments());
			}

			void GuiDocumentCommonInterface::InvokeModifiedChanged()
			{
				ModifiedChanged.Execute(documentControl->GetNotifyEventArguments());
			}

			void GuiDocumentCommonInterface::UpdateCaretPoint()
			{
				GuiGraphicsHost* host=documentComposition->GetRelatedGraphicsHost();
				if(host)
				{
					Rect caret=documentElement->GetCaretBounds(documentElement->GetCaretEnd(), documentElement->IsCaretEndPreferFrontSide());
					Point view=GetDocumentViewPosition();
					vint x=caret.x1-view.x;
					vint y=caret.y2-view.y;
					host->SetCaretPoint(Point(x, y), documentComposition);
				}
			}

			void GuiDocumentCommonInterface::EnsureDocumentRectVisible(Rect bounds)
			{
				if (bounds != Rect())
				{
					bounds.x1 -= 15;
					bounds.y1 -= 15;
					bounds.x2 += 15;
					bounds.y2 += 15;
					EnsureRectVisible(bounds);
				}
			}

			void GuiDocumentCommonInterface::Move(TextPos caret, bool shift, bool frontSide)
			{
				TextPos begin=documentElement->GetCaretBegin();
				TextPos end=documentElement->GetCaretEnd();
				
				TextPos newBegin=shift?begin:caret;
				TextPos newEnd=caret;
				documentElement->SetCaret(newBegin, newEnd, frontSide);
				if (editMode != GuiDocumentEditMode::ViewOnly && documentControl && documentControl->GetVisuallyEnabled() && documentControl->GetFocused())
				{
					documentElement->SetCaretVisible(true);
				}
				UpdateCaretPoint();
				SelectionChanged.Execute(documentControl->GetNotifyEventArguments());

				EnsureDocumentRectVisible(documentElement->GetCaretBounds(newEnd, frontSide));
			}

			bool GuiDocumentCommonInterface::ProcessKey(VKEY code, bool shift, bool ctrl)
			{
				if (IGuiShortcutKeyItem* item = internalShortcutKeyManager->TryGetShortcut(ctrl, shift, false, code))
				{
					GuiEventArgs arguments(documentControl->GetBoundsComposition());
					item->Executed.Execute(arguments);
					return true;
				}

				TextPos currentCaret = documentElement->GetCaretEnd();
				bool frontSide = documentElement->IsCaretEndPreferFrontSide();
				TextPos begin = documentElement->GetCaretBegin();
				TextPos end = documentElement->GetCaretEnd();

				switch (code)
				{
				case VKEY::KEY_UP:
					{
						TextPos newCaret = documentElement->CalculateCaret(currentCaret, IGuiGraphicsParagraph::CaretMoveUp, frontSide);
						Move(newCaret, shift, frontSide);
					}
					break;
				case VKEY::KEY_DOWN:
					{
						TextPos newCaret = documentElement->CalculateCaret(currentCaret, IGuiGraphicsParagraph::CaretMoveDown, frontSide);
						Move(newCaret, shift, frontSide);
					}
					break;
				case VKEY::KEY_LEFT:
					{
						TextPos newCaret = documentElement->CalculateCaret(currentCaret, IGuiGraphicsParagraph::CaretMoveLeft, frontSide);
						Move(newCaret, shift, frontSide);
					}
					break;
				case VKEY::KEY_RIGHT:
					{
						TextPos newCaret = documentElement->CalculateCaret(currentCaret, IGuiGraphicsParagraph::CaretMoveRight, frontSide);
						Move(newCaret, shift, frontSide);
					}
					break;
				case VKEY::KEY_HOME:
					{
						if (ctrl)
						{
							Move(TextPos(0, 0), shift, true);
							break;
						}

						TextPos newCaret = documentElement->CalculateCaret(currentCaret, IGuiGraphicsParagraph::CaretLineFirst, frontSide);
						if (newCaret == currentCaret)
						{
							newCaret = documentElement->CalculateCaret(currentCaret, IGuiGraphicsParagraph::CaretFirst, frontSide);
						}
						if (newCaret == currentCaret)
						{
							newCaret = TextPos(0, 0);
						}
						Move(newCaret, shift, frontSide);
					}
					break;
				case VKEY::KEY_END:
					{
						if (ctrl)
						{
							vint lastIndex = documentElement->GetDocument()->paragraphs.Count() - 1;
							auto lastParagraph = documentElement->GetDocument()->paragraphs[lastIndex];
							Move(TextPos(lastIndex, lastParagraph->GetTextForCaret().Length()), shift, false);
							break;
						}

						TextPos newCaret = documentElement->CalculateCaret(currentCaret, IGuiGraphicsParagraph::CaretLineLast, frontSide);
						if (newCaret == currentCaret)
						{
							newCaret = documentElement->CalculateCaret(currentCaret, IGuiGraphicsParagraph::CaretLast, frontSide);
						}
						if (newCaret == currentCaret)
						{
							vint lastIndex = documentElement->GetDocument()->paragraphs.Count() - 1;
							auto lastParagraph = documentElement->GetDocument()->paragraphs[lastIndex];
							newCaret = TextPos(lastIndex, lastParagraph->GetTextForCaret().Length());
						}
						Move(newCaret, shift, frontSide);
					}
					break;
				case VKEY::KEY_PRIOR:
				case VKEY::KEY_NEXT:
					{
						if (config.paragraphMode == GuiDocumentParagraphMode::Singleline) break;
						if (!documentMouseArea) break;
						vint page = documentMouseArea->GetCachedBounds().Height();
						if (page <= 0) break;

						Rect caretBounds = documentElement->GetCaretBounds(currentCaret, frontSide);
						vint x = caretBounds.x1;
						vint y = (caretBounds.y1 + caretBounds.y2) / 2;
						y += (code == VKEY::KEY_PRIOR ? -page : page);

						TextPos newCaret = documentElement->CalculateCaretFromPoint(Point(x, y));
						Move(newCaret, shift, frontSide);
					}
					break;
				case VKEY::KEY_BACK:
					if (editMode == GuiDocumentEditMode::Editable)
					{
						if (begin == end)
						{
							ProcessKey(VKEY::KEY_LEFT, true, false);
						}
						Array<WString> text;
						EditText(documentElement->GetCaretBegin(), documentElement->GetCaretEnd(), documentElement->IsCaretEndPreferFrontSide(), text);
						return true;
					}
					break;
				case VKEY::KEY_DELETE:
					if (editMode == GuiDocumentEditMode::Editable)
					{
						if (begin == end)
						{
							ProcessKey(VKEY::KEY_RIGHT, true, false);
						}
						Array<WString> text;
						EditText(documentElement->GetCaretBegin(), documentElement->GetCaretEnd(), documentElement->IsCaretEndPreferFrontSide(), text);
						return true;
					}
					break;
				case VKEY::KEY_RETURN:
					if (editMode == GuiDocumentEditMode::Editable)
					{
						if (config.paragraphMode == GuiDocumentParagraphMode::Singleline)
						{
							// Singleline text boxes should ignore Enter entirely.
							// In particular, Enter must not delete selection.
							return true;
						}
						else if (ctrl && config.paragraphMode == GuiDocumentParagraphMode::Paragraph)
						{
							Array<WString> text(1);
							text[0] = L"\r\n";
							EditText(documentElement->GetCaretBegin(), documentElement->GetCaretEnd(), documentElement->IsCaretEndPreferFrontSide(), text);
						}
						else
						{
							Array<WString> text(2);
							EditText(documentElement->GetCaretBegin(), documentElement->GetCaretEnd(), documentElement->IsCaretEndPreferFrontSide(), text);
						}
						return true;
					}
					break;
				default:;
				}
				return false;
			}

			void GuiDocumentCommonInterface::InstallDocumentViewer(
				GuiControl* _sender,
				compositions::GuiGraphicsComposition* _mouseArea,
				compositions::GuiGraphicsComposition* _container,
				compositions::GuiGraphicsComposition* eventComposition,
				compositions::GuiGraphicsComposition* focusableComposition
			)
			{
				documentControl = _sender;

				documentElement = GuiDocumentElement::Create();
				documentElement->SetCallback(this);
				documentElement->SetParagraphPadding(config.paragraphPadding);
				documentElement->SetWrapLine(config.wrapLine);
				documentElement->SetParagraphRecycle(config.paragraphRecycle);

				documentComposition = new GuiBoundsComposition;
				documentComposition->SetOwnedElement(Ptr(documentElement));
				documentComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElement);
				documentComposition->SetAlignmentToParent(Margin(2, 2, 2, 2));
				_container->AddChild(documentComposition);
				ReplaceMouseArea(_mouseArea);

				focusableComposition->GetEventReceiver()->caretNotify.AttachMethod(this, &GuiDocumentCommonInterface::OnCaretNotify);
				focusableComposition->GetEventReceiver()->gotFocus.AttachMethod(this, &GuiDocumentCommonInterface::OnGotFocus);
				focusableComposition->GetEventReceiver()->lostFocus.AttachMethod(this, &GuiDocumentCommonInterface::OnLostFocus);
				focusableComposition->GetEventReceiver()->keyDown.AttachMethod(this, &GuiDocumentCommonInterface::OnKeyDown);
				focusableComposition->GetEventReceiver()->charInput.AttachMethod(this, &GuiDocumentCommonInterface::OnCharInput);

				undoRedoProcessor->Setup(documentElement, documentComposition);
				ActiveHyperlinkChanged.SetAssociatedComposition(eventComposition);
				ActiveHyperlinkExecuted.SetAssociatedComposition(eventComposition);
				SelectionChanged.SetAssociatedComposition(eventComposition);
				UndoRedoChanged.SetAssociatedComposition(eventComposition);
				ModifiedChanged.SetAssociatedComposition(eventComposition);

				undoRedoProcessor->UndoRedoChanged.Add(this, &GuiDocumentCommonInterface::InvokeUndoRedoChanged);
				undoRedoProcessor->ModifiedChanged.Add(this, &GuiDocumentCommonInterface::InvokeModifiedChanged);
				SetDocument(Ptr(new DocumentModel));
			}

			void GuiDocumentCommonInterface::ReplaceMouseArea(compositions::GuiGraphicsComposition* _mouseArea)
			{
				if (documentMouseArea)
				{
					if (documentMouseArea->GetAssociatedCursor() == documentCursor)
					{
						documentMouseArea->SetAssociatedCursor(nullptr);
					}

					documentMouseArea->GetEventReceiver()->mouseMove.Detach(onMouseMoveHandler);
					documentMouseArea->GetEventReceiver()->leftButtonDown.Detach(onMouseDownHandler);
					documentMouseArea->GetEventReceiver()->leftButtonUp.Detach(onMouseUpHandler);
					documentMouseArea->GetEventReceiver()->mouseLeave.Detach(onMouseLeaveHandler);

					onMouseMoveHandler = nullptr;
					onMouseDownHandler = nullptr;
					onMouseUpHandler = nullptr;
					onMouseLeaveHandler = nullptr;
				}
				documentMouseArea = _mouseArea;
				if (documentMouseArea)
				{
					if (documentCursor)
					{
						documentMouseArea->SetAssociatedCursor(documentCursor);
					}

					onMouseMoveHandler = documentMouseArea->GetEventReceiver()->mouseMove.AttachMethod(this, &GuiDocumentCommonInterface::OnMouseMove);
					onMouseDownHandler = documentMouseArea->GetEventReceiver()->leftButtonDown.AttachMethod(this, &GuiDocumentCommonInterface::OnMouseDown);
					onMouseUpHandler = documentMouseArea->GetEventReceiver()->leftButtonUp.AttachMethod(this, &GuiDocumentCommonInterface::OnMouseUp);
					onMouseLeaveHandler = documentMouseArea->GetEventReceiver()->mouseLeave.AttachMethod(this, &GuiDocumentCommonInterface::OnMouseLeave);
				}
			}

			void GuiDocumentCommonInterface::SetActiveHyperlink(Ptr<DocumentHyperlinkRun::Package> package)
			{
				auto normalizedPackage =
					!package ? nullptr :
					package->hyperlinks.Count() == 0 ? nullptr :
					package;

				if (!activeHyperlinks && !normalizedPackage) return;
				if (activeHyperlinks && normalizedPackage)
				{
					if (CompareEnumerable(activeHyperlinks->hyperlinks, normalizedPackage->hyperlinks) == 0) return;
				}

				ActivateActiveHyperlink(false);
				activeHyperlinks = normalizedPackage;
				ActivateActiveHyperlink(true);
				ActiveHyperlinkChanged.Execute(documentControl->GetNotifyEventArguments());
			}

			void GuiDocumentCommonInterface::ActivateActiveHyperlink(bool activate)
			{
				if (activeHyperlinks)
				{
					for (auto run : activeHyperlinks->hyperlinks)
					{
						run->styleName = activate ? run->activeStyleName : run->normalStyleName;
					}
					documentElement->NotifyParagraphUpdated(activeHyperlinks->row, 1, 1, false);
				}
			}

			void GuiDocumentCommonInterface::AddShortcutCommand(VKEY key, const Func<void()>& eventHandler)
			{
				IGuiShortcutKeyItem* item=internalShortcutKeyManager->CreateNewShortcut(true, false, false, key);
				item->Executed.AttachLambda([=](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
				{
					eventHandler();
				});
			}

			void GuiDocumentCommonInterface::EditTextInternal(TextPos begin, TextPos end, const Func<void(TextPos, TextPos, vint&, vint&)>& editor, bool clearUndoRedo)
			{
				// save run before editing
				if(begin>end)
				{
					TextPos temp=begin;
					begin=end;
					end=temp;
				}
				Ptr<DocumentModel> originalModel=documentElement->GetDocument()->CopyDocument(begin, end, true);
				if(originalModel)
				{
					// edit
					vint paragraphCount=0;
					vint lastParagraphLength=0;
					editor(begin, end, paragraphCount, lastParagraphLength);

					// calculate new caret
					TextPos caret;
					if(paragraphCount==0)
					{
						caret=begin;
					}
					else if(paragraphCount==1)
					{
						caret=TextPos(begin.row, begin.column+lastParagraphLength);
					}
					else
					{
						caret=TextPos(begin.row+paragraphCount-1, lastParagraphLength);
					}
					documentElement->SetCaret(caret, caret, true);
					EnsureDocumentRectVisible(documentElement->GetCaretBounds(caret, true));
					documentControl->TextChanged.Execute(documentControl->GetNotifyEventArguments());
					UpdateCaretPoint();
					SelectionChanged.Execute(documentControl->GetNotifyEventArguments());

					if (clearUndoRedo)
					{
						undoRedoProcessor->ClearUndoRedo();
					}
					else
					{
						// save run after editing
						Ptr<DocumentModel> inputModel = documentElement->GetDocument()->CopyDocument(begin, caret, true);

						// submit redo-undo
						GuiDocumentUndoRedoProcessor::ReplaceModelStruct arguments;
						arguments.originalStart = begin;
						arguments.originalEnd = end;
						arguments.originalModel = originalModel;
						arguments.inputStart = begin;
						arguments.inputEnd = caret;
						arguments.inputModel = inputModel;
						undoRedoProcessor->OnReplaceModel(arguments);
					}
				}
			}

			void GuiDocumentCommonInterface::EditStyleInternal(TextPos begin, TextPos end, const Func<void(TextPos, TextPos)>& editor)
			{
				// save run before editing
				if(begin>end)
				{
					TextPos temp=begin;
					begin=end;
					end=temp;
				}
				Ptr<DocumentModel> originalModel=documentElement->GetDocument()->CopyDocument(begin, end, true);
				if(originalModel)
				{
					// edit
					editor(begin, end);

					// save run after editing
					Ptr<DocumentModel> inputModel=documentElement->GetDocument()->CopyDocument(begin, end, true);

					// submit redo-undo
					GuiDocumentUndoRedoProcessor::ReplaceModelStruct arguments;
					arguments.originalStart=begin;
					arguments.originalEnd=end;
					arguments.originalModel=originalModel;
					arguments.inputStart=begin;
					arguments.inputEnd=end;
					arguments.inputModel=inputModel;
					undoRedoProcessor->OnReplaceModel(arguments);
				}
			}

			void GuiDocumentCommonInterface::MergeBaselineAndDefaultFont(Ptr<DocumentModel> document)
			{
				document->MergeDefaultFont(documentControl->GetDisplayFont());
				if (baselineDocument)
				{
					document->MergeBaselineStyles(baselineDocument);
				}
			}

			void GuiDocumentCommonInterface::OnFontChanged()
			{
				auto document = documentElement->GetDocument();
				MergeBaselineAndDefaultFont(document);
				auto paragraphCount = document->paragraphs.Count();
				if (paragraphCount > 0)
				{
					documentElement->NotifyParagraphUpdated(0, paragraphCount, paragraphCount, false);
				}
			}

			void GuiDocumentCommonInterface::OnCaretNotify(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (documentControl->GetVisuallyEnabled() && editMode != GuiDocumentEditMode::ViewOnly)
				{
					documentElement->BlinkCaret();
				}
			}

			void GuiDocumentCommonInterface::OnGotFocus(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (documentControl->GetVisuallyEnabled() && editMode != GuiDocumentEditMode::ViewOnly)
				{
					documentElement->SetCaretVisible(true);
					UpdateCaretPoint();
				}
			}

			void GuiDocumentCommonInterface::OnLostFocus(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if(documentControl->GetVisuallyEnabled())
				{
					documentElement->SetCaretVisible(false);
				}
			}

			void GuiDocumentCommonInterface::OnKeyDown(compositions::GuiGraphicsComposition* sender, compositions::GuiKeyEventArgs& arguments)
			{
				if (documentControl->GetVisuallyEnabled())
				{
					if (editMode != GuiDocumentEditMode::ViewOnly)
					{
						if (ProcessKey(arguments.code, arguments.shift, arguments.ctrl))
						{
							arguments.handled = true;
						}
					}
				}
			}

			void GuiDocumentCommonInterface::OnCharInput(compositions::GuiGraphicsComposition* sender, compositions::GuiCharEventArgs& arguments)
			{
				if (documentControl->GetVisuallyEnabled())
				{
					if (editMode == GuiDocumentEditMode::Editable &&
						arguments.code != (wchar_t)VKEY::KEY_ESCAPE &&
						arguments.code != (wchar_t)VKEY::KEY_BACK &&
						arguments.code != (wchar_t)VKEY::KEY_RETURN &&
						(arguments.code != (wchar_t)VKEY::KEY_TAB || documentControl->GetAcceptTabInput()) &&
						!arguments.ctrl)
					{
						Array<WString> text(1);
						text[0] = WString::FromChar(arguments.code);
						EditText(documentElement->GetCaretBegin(), documentElement->GetCaretEnd(), documentElement->IsCaretEndPreferFrontSide(), text);
					}
				}
			}

			void GuiDocumentCommonInterface::UpdateCursor(INativeCursor* cursor)
			{
				documentCursor = cursor;
				if (documentMouseArea)
				{
					documentMouseArea->SetAssociatedCursor(cursor);
				}
			}

			Point GuiDocumentCommonInterface::GetMouseOffset()
			{
				if (documentMouseArea)
				{
					auto documentBounds = documentComposition->GetGlobalBounds();
					auto mouseAreaBounds = documentMouseArea->GetGlobalBounds();
					return Point(
						documentBounds.x1 - mouseAreaBounds.x1,
						documentBounds.y1 - mouseAreaBounds.y1
					);
				}
				else
				{
					return Point(0, 0);
				}
			}

			void GuiDocumentCommonInterface::OnMouseMove(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
			{
				auto offset = GetMouseOffset();
				auto x = arguments.x - offset.x;
				auto y = arguments.y - offset.y;

				if(documentControl->GetVisuallyEnabled())
				{
					switch(editMode)
					{
					case GuiDocumentEditMode::ViewOnly:
						{
							auto package = documentElement->GetHyperlinkFromPoint({ x, y });
							bool handCursor = false;

							if(dragging)
							{
								if(activeHyperlinks)
								{
									if (package && CompareEnumerable(activeHyperlinks->hyperlinks, package->hyperlinks) == 0)
									{
										ActivateActiveHyperlink(true);
										handCursor = true;
									}
									else
									{
										ActivateActiveHyperlink(false);
									}
								}
							}
							else
							{
								SetActiveHyperlink(package);
								handCursor = activeHyperlinks;
							}

							if(handCursor)
							{
								auto cursor = GetCurrentController()->ResourceService()->GetSystemCursor(INativeCursor::Hand);
								UpdateCursor(cursor);
							}
							else
							{
								UpdateCursor(nullptr);
							}
						}
						break;
					case GuiDocumentEditMode::Selectable:
					case GuiDocumentEditMode::Editable:
						if(dragging)
						{
							TextPos caret=documentElement->CalculateCaretFromPoint(Point(x, y));
							TextPos oldCaret=documentElement->GetCaretBegin();
							Move(caret, true, (oldCaret==caret?documentElement->IsCaretEndPreferFrontSide():caret<oldCaret));
						}
						break;
					}
				}
			}

			void GuiDocumentCommonInterface::OnMouseDown(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
			{
				auto offset = GetMouseOffset();
				auto x = arguments.x - offset.x;
				auto y = arguments.y - offset.y;

				if(documentControl->GetVisuallyEnabled())
				{
					switch(editMode)
					{
					case GuiDocumentEditMode::ViewOnly:
						SetActiveHyperlink(documentElement->GetHyperlinkFromPoint({ x, y }));
						break;
					case GuiDocumentEditMode::Selectable:
					case GuiDocumentEditMode::Editable:
						{
							documentControl->SetFocused();
							TextPos caret=documentElement->CalculateCaretFromPoint(Point(x, y));
							TextPos oldCaret=documentElement->GetCaretEnd();
							if(caret!=oldCaret)
							{
								Move(caret, arguments.shift, caret<oldCaret);
							}
						}
						break;
					}
					dragging=true;
				}
			}

			void GuiDocumentCommonInterface::OnMouseUp(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments)
			{
				auto offset = GetMouseOffset();
				auto x = arguments.x - offset.x;
				auto y = arguments.y - offset.y;

				if(documentControl->GetVisuallyEnabled())
				{
					dragging=false;
					switch(editMode)
					{
					case GuiDocumentEditMode::ViewOnly:
						{
							auto package = documentElement->GetHyperlinkFromPoint({ x, y });
							if(activeHyperlinks)
							{
								if (package && CompareEnumerable(activeHyperlinks->hyperlinks, package->hyperlinks) == 0)
								{
									ActiveHyperlinkExecuted.Execute(documentControl->GetNotifyEventArguments());
								}
								else
								{
									SetActiveHyperlink(nullptr);
								}
							}
						}
						break;
					default:;
					}
				}
			}

			void GuiDocumentCommonInterface::OnMouseLeave(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				SetActiveHyperlink(nullptr);
				if (editMode == GuiDocumentEditMode::ViewOnly)
				{
					UpdateCursor(nullptr);
				}
			}

			//================ callback

			void GuiDocumentCommonInterface::OnStartRender()
			{
				for (auto item : documentItems.Values())
				{
					item->visible = false;
				}
			}

			void GuiDocumentCommonInterface::OnFinishRender()
			{
				for (auto item : documentItems.Values())
				{
					if (item->container->GetVisible() != item->visible)
					{
						item->container->SetVisible(item->visible);
					}
				}
			}

			Size GuiDocumentCommonInterface::OnRenderEmbeddedObject(const WString& name, const Rect& location)
			{
				vint index = documentItems.Keys().IndexOf(name);
				if (index != -1)
				{
					auto item = documentItems.Values()[index];
					auto size = item->container->GetCachedBounds().GetSize();
					item->container->SetExpectedBounds(Rect(location.LeftTop(), Size(0, 0)));
					item->visible = true;
					return size;
				}
				return Size();
			}

			//================ basic

			struct FetchLineRecord
			{
				const wchar_t*			begin = nullptr;
				const wchar_t*			end = nullptr;
				const wchar_t*			next = nullptr;
			};

			FetchLineRecord FetchLineRecord_Init(const wchar_t* text)
			{
				return { text,text,nullptr };
			}

			FetchLineRecord FetchLineRecord_Join(const FetchLineRecord& flr1, const FetchLineRecord& flr2)
			{
				return { flr1.begin, flr2.end, flr2.next };
			}

			void FetchLineRecord_Next(FetchLineRecord& record)
			{
				while (*record.end != '\n' && *record.end != '\0') record.end++;
				record.next = record.end;
				while (record.end > record.begin && record.end[-1] == L'\r') record.end--;
				if (*record.next == '\n') record.next++;
			}

			WString FetchLineRecord_Get(const FetchLineRecord& flr, const wchar_t* buffer, const WString& text)
			{
				return text.Sub(flr.begin - buffer, flr.end - flr.begin);
			}

			void GuiDocumentCommonInterface::UserInput_ConvertToPlainText(Ptr<DocumentModel> model, vint beginParagraph, vint endParagraph)
			{
				if (beginParagraph > endParagraph) return;

				RunRangeMap runRanges;
				document_editor::GetRunRange(model->paragraphs[endParagraph].Obj(), runRanges);

				TextPos begin(beginParagraph, 0);
				TextPos end(endParagraph, runRanges[model->paragraphs[endParagraph].Obj()].end);
				model->ConvertToPlainText(begin, end);

				for (vint i = beginParagraph; i <= endParagraph; i++)
				{
					model->paragraphs[i]->alignment.Reset();
				}
			}

			void GuiDocumentCommonInterface::UserInput_JoinParagraphs(collections::List<WString>& paragraphTexts, bool spaceForFlattenedLineBreak)
			{
				auto line = stream::GenerateToStream([&](stream::StreamWriter& writer)
				{
					for(auto [paragraph, index] : indexed(paragraphTexts))
					{
						if (index > 0 && spaceForFlattenedLineBreak)
						{
							writer.WriteChar(L' ');
						}
						writer.WriteString(paragraph);
					}
				});
				paragraphTexts.Clear();
				paragraphTexts.Add(line);
			}

			void GuiDocumentCommonInterface::UserInput_JoinParagraphs(Ptr<DocumentModel> model, bool spaceForFlattenedLineBreak)
			{
				auto firstParagraph = model->paragraphs[0];
				for (auto paragraph : From(model->paragraphs).Skip(1))
				{
					if (spaceForFlattenedLineBreak)
					{
						auto textRun = Ptr(new DocumentTextRun);
						textRun->text = WString::Unmanaged(L" ");
						firstParagraph->runs.Add(textRun);
					}
					CopyFrom(firstParagraph->runs, paragraph->runs, true);
				}
				model->paragraphs.Clear();
				model->paragraphs.Add(firstParagraph);
			}

			void GuiDocumentCommonInterface::UserInput_JoinLinesInsideParagraph(WString& text, bool spaceForFlattenedLineBreak)
			{
				const wchar_t* buffer = text.Buffer();
				auto flr = FetchLineRecord_Init(buffer);
				FetchLineRecord_Next(flr);
				if (!*flr.next)
				{
					bool addSpace = flr.end < flr.next && flr.next[-1] != L'\r' && spaceForFlattenedLineBreak;
					text = FetchLineRecord_Get(flr, buffer, text);
					if (addSpace)
					{
						text += WString::Unmanaged(L" ");
					}
					return;
				}

				text = stream::GenerateToStream([&](stream::StreamWriter& writer)
				{
					writer.WriteString(FetchLineRecord_Get(flr, buffer, text));
					while (*flr.end)
					{
						if (spaceForFlattenedLineBreak)
						{
							writer.WriteChar(L' ');
						}

						flr = FetchLineRecord_Init(flr.next);
						FetchLineRecord_Next(flr);
						writer.WriteString(FetchLineRecord_Get(flr, buffer, text));
					}
				});
			}

			void GuiDocumentCommonInterface::UserInput_JoinLinesInsideParagraph(Ptr<DocumentParagraphRun> paragraph, bool spaceForFlattenedLineBreak)
			{
				List<Ptr<DocumentContainerRun>> containers;
				containers.Add(paragraph);

				for (vint i = 0; i < containers.Count(); i++)
				{
					auto container = containers[i];
					for (auto run : container->runs)
					{
						if (auto subContainer = run.Cast<DocumentContainerRun>())
						{
							containers.Add(subContainer);
						}
						else if (auto textRun = run.Cast<DocumentTextRun>())
						{
							UserInput_JoinLinesInsideParagraph(textRun->text, spaceForFlattenedLineBreak);
						}
					}
				}
			}

			void GuiDocumentCommonInterface::UserInput_FormatText(collections::List<WString>& paragraphTexts, const GuiDocumentConfigEvaluated& config)
			{
				if (config.paragraphMode != GuiDocumentParagraphMode::Paragraph)
				{
					for (vint i = 0; i < paragraphTexts.Count(); i++)
					{
						UserInput_JoinLinesInsideParagraph(paragraphTexts[i], config.spaceForFlattenedLineBreak);
					}
				}
				if (config.paragraphMode == GuiDocumentParagraphMode::Singleline)
				{
					UserInput_JoinParagraphs(paragraphTexts, config.spaceForFlattenedLineBreak);
				}
			}

			void GuiDocumentCommonInterface::UserInput_FormatText(const WString& text, collections::List<WString>& paragraphTexts, const GuiDocumentConfigEvaluated& config)
			{
				if (config.doubleLineBreaksBetweenParagraph)
				{
					const wchar_t* buffer = text.Buffer();
					auto flr = FetchLineRecord_Init(buffer);
					FetchLineRecord_Next(flr);
					bool remaining = false;
					while (*flr.begin)
					{
						paragraphTexts.Add(stream::GenerateToStream([&](stream::StreamWriter& writer)
						{
							auto flrFragmentFirst = flr;
							auto flrFragmentLast = flrFragmentFirst;
							auto SubmitFragment = [&](bool endingEmptyLines)
							{
								auto flrFragment = FetchLineRecord_Join(flrFragmentFirst, flrFragmentLast);
								writer.WriteString(FetchLineRecord_Get(flrFragment, buffer, text));
								if (flrFragment.end != flrFragment.next && endingEmptyLines)
								{
									if (config.paragraphMode == GuiDocumentParagraphMode::Paragraph)
									{
										writer.WriteString(L"\r\n");
									}
									else if (config.spaceForFlattenedLineBreak)
									{
										writer.WriteChar(L' ');
									}
								}
							};

							while (true)
							{
								if (!*flrFragmentLast.next)
								{
									SubmitFragment(true);
									flr = FetchLineRecord_Init(flrFragmentLast.next);
									remaining = false;
									return;
								}

								auto flrNext = FetchLineRecord_Init(flrFragmentLast.next);
								FetchLineRecord_Next(flrNext);
								if (flrNext.end == flrNext.begin)
								{
									SubmitFragment(false);
									flr = FetchLineRecord_Init(flrNext.next);
									FetchLineRecord_Next(flr);
									remaining = true;
									return;
								}

								if (flrFragmentLast.next - flrFragmentLast.end == 2)
								{
									flrFragmentLast = flrNext;
								}
								else
								{
									SubmitFragment(true);
									flrFragmentFirst = flrNext;
									flrFragmentLast = flrNext;
								}
							}
						}));
					}

					if (remaining)
					{
						paragraphTexts.Add(WString::Empty);
					}
				}
				else
				{
					stream::StringReader reader(text);
					while (!reader.IsEnd())
					{
						WString line = reader.ReadLine();
						paragraphTexts.Add(line);
					}
				}

				if (config.paragraphMode == GuiDocumentParagraphMode::Singleline)
				{
					UserInput_JoinParagraphs(paragraphTexts, config.spaceForFlattenedLineBreak);
				}
			}

			void GuiDocumentCommonInterface::UserInput_FormatDocument(Ptr<DocumentModel> model, Ptr<DocumentModel> baselineDocument, const GuiDocumentConfigEvaluated& config)
			{
				if (!model) return;
				if (config.pasteAsPlainText)
				{
					UserInput_ConvertToPlainText(model, 0, model->paragraphs.Count() - 1);

					if (baselineDocument)
					{
						CopyFrom(model->styles, baselineDocument->styles);
					}
					else
					{
						model->styles.Clear();
					}
				}

				if (model->paragraphs.Count() == 0)
				{
					return;
				}

				if (config.paragraphMode != GuiDocumentParagraphMode::Paragraph)
				{
					for (auto paragraph : model->paragraphs)
					{
						UserInput_JoinLinesInsideParagraph(paragraph, config.spaceForFlattenedLineBreak);
					}
				}
				if (config.paragraphMode == GuiDocumentParagraphMode::Singleline)
				{
					UserInput_JoinParagraphs(model, config.spaceForFlattenedLineBreak);
				}
			}

			WString GuiDocumentCommonInterface::UserInput_ConvertDocumentToText(Ptr<DocumentModel> model)
			{
				return model->GetTextForReading(WString::Unmanaged(config.doubleLineBreaksBetweenParagraph ? L"\r\n\r\n" : L"\r\n"));
			}

			GuiDocumentCommonInterface::GuiDocumentCommonInterface(const GuiDocumentConfig& _config)
				: config(_config)
			{
				undoRedoProcessor = Ptr(new GuiDocumentUndoRedoProcessor);
				internalShortcutKeyManager = Ptr(new GuiShortcutKeyManager);
				AddShortcutCommand(VKEY::KEY_Z, Func<bool()>(this, &GuiDocumentCommonInterface::Undo));
				AddShortcutCommand(VKEY::KEY_Y, Func<bool()>(this, &GuiDocumentCommonInterface::Redo));
				AddShortcutCommand(VKEY::KEY_A, Func<void()>(this, &GuiDocumentCommonInterface::SelectAll));
				AddShortcutCommand(VKEY::KEY_X, Func<bool()>(this, &GuiDocumentCommonInterface::Cut));
				AddShortcutCommand(VKEY::KEY_C, Func<bool()>(this, &GuiDocumentCommonInterface::Copy));
				AddShortcutCommand(VKEY::KEY_V, Func<bool()>(this, &GuiDocumentCommonInterface::Paste));
			}

			GuiDocumentCommonInterface::~GuiDocumentCommonInterface()
			{
			}

			Ptr<DocumentModel> GuiDocumentCommonInterface::GetDocument()
			{
				return documentElement->GetDocument();
			}

			void GuiDocumentCommonInterface::SetDocument(Ptr<DocumentModel> value)
			{
				value = value ? value->CopyDocument() : nullptr;
				UserInput_FormatDocument(value, baselineDocument, config);
				SetActiveHyperlink(0);
				ClearUndoRedo();
				NotifyModificationSaved();

				if (value)
				{
					if (value->paragraphs.Count() == 0)
					{
						value->paragraphs.Add(Ptr(new DocumentParagraphRun));
					}
					MergeBaselineAndDefaultFont(value);
				}

				documentElement->SetDocument(value);
			}

			//================ document items

			bool GuiDocumentCommonInterface::AddDocumentItem(Ptr<GuiDocumentItem> value)
			{
				if (documentItems.Keys().Contains(value->GetName()))
				{
					return false;
				}
				documentItems.Add(value->GetName(), value);
				documentComposition->AddChild(value->container);
				value->visible = false;
				value->owned = true;
				value->container->SetVisible(false);
				return true;
			}

			bool GuiDocumentCommonInterface::RemoveDocumentItem(Ptr<GuiDocumentItem> value)
			{
				vint index = documentItems.Keys().IndexOf(value->GetName());
				if (index == -1)
				{
					return false;
				}
				if (documentItems.Values()[index] != value)
				{
					return false;
				}
				value->owned = false;
				documentComposition->RemoveChild(value->container);
				documentItems.Remove(value->GetName());
				return true;
			}

			const GuiDocumentCommonInterface::DocumentItemMap& GuiDocumentCommonInterface::GetDocumentItems()
			{
				return documentItems;
			}

			//================ caret operations

			TextPos GuiDocumentCommonInterface::GetCaretBegin()
			{
				return documentElement->GetCaretBegin();
			}

			TextPos GuiDocumentCommonInterface::GetCaretEnd()
			{
				return documentElement->GetCaretEnd();
			}

			void GuiDocumentCommonInterface::SetCaret(TextPos begin, TextPos end)
			{
				documentElement->SetCaret(begin, end, end>=begin);
				UpdateCaretPoint();
				SelectionChanged.Execute(documentControl->GetNotifyEventArguments());
			}

			void GuiDocumentCommonInterface::EnsureCaretVisible()
			{
				auto end = documentElement->GetCaretEnd();
				auto frontSide = documentElement->IsCaretEndPreferFrontSide();
				EnsureDocumentRectVisible(documentElement->GetCaretBounds(end, frontSide));
			}

			TextPos GuiDocumentCommonInterface::CalculateCaretFromPoint(Point point)
			{
				return documentElement->CalculateCaretFromPoint(point);
			}

			Rect GuiDocumentCommonInterface::GetCaretBounds(TextPos caret, bool frontSide)
			{
				return documentElement->GetCaretBounds(caret, frontSide);
			}

			//================ editing operations

			void GuiDocumentCommonInterface::NotifyParagraphUpdated(vint index, vint oldCount, vint newCount, bool updatedText, bool skipFormatting)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::GuiDocumentCommonInterface::NotifyParagraphUpdated(vint, vint, vint, bool, bool)#"
				auto model = documentElement->GetDocument();
				if (config.paragraphMode == GuiDocumentParagraphMode::Singleline)
				{
					CHECK_ERROR(model->paragraphs.Count() <= 1, ERROR_MESSAGE_PREFIX L"In Singleline mode, there should be no more than 1 paragraphs in the document.");
				}

				if (0 <= index && index + newCount <= model->paragraphs.Count())
				{
					if (config.pasteAsPlainText && updatedText)
					{
						if(!skipFormatting)
						{
							UserInput_ConvertToPlainText(model, index, index + newCount - 1);
						}
						if (baselineDocument)
						{
							CopyFrom(model->styles, baselineDocument->styles);
						}
						else
						{
							model->styles.Clear();
						}
					}

					if (config.paragraphMode != GuiDocumentParagraphMode::Paragraph && !skipFormatting)
					{
						for (vint i = index; i < index + newCount; i++)
						{
							UserInput_JoinLinesInsideParagraph(model->paragraphs[i], config.spaceForFlattenedLineBreak);
						}
					}

					documentElement->NotifyParagraphUpdated(index, oldCount, newCount, updatedText);
				}
#undef ERROR_MESSAGE_PREFIX
			}

			void GuiDocumentCommonInterface::EditRun(TextPos begin, TextPos end, Ptr<DocumentModel> model, bool copy, bool skipFormatting)
			{
				if (!skipFormatting)
				{
					UserInput_FormatDocument(model, baselineDocument, config);
				}
				EditTextInternal(begin, end, [=, this](TextPos begin, TextPos end, vint& paragraphCount, vint& lastParagraphLength)
				{
					documentElement->EditRun(begin, end, model, copy);
					paragraphCount=model->paragraphs.Count();
					lastParagraphLength=paragraphCount==0?0:model->paragraphs[paragraphCount-1]->GetTextForCaret().Length();
				});
			}

			void GuiDocumentCommonInterface::EditText(TextPos begin, TextPos end, bool frontSide, const collections::Array<WString>& text, bool skipFormatting)
			{
				EditTextInternal(begin, end, [=, this, &text](TextPos begin, TextPos end, vint& paragraphCount, vint& lastParagraphLength)
				{
					Array<WString> updatedText;
					bool useUpdatedText = config.paragraphMode != GuiDocumentParagraphMode::Paragraph && !skipFormatting;
					if (useUpdatedText)
					{
						List<WString> paragraphTexts;
						CopyFrom(paragraphTexts, text);
						UserInput_FormatText(paragraphTexts, config);
						CopyFrom(updatedText, paragraphTexts);
					}

					const Array<WString>& textToUse = useUpdatedText ? updatedText : text;
					documentElement->EditText(begin, end, frontSide, textToUse);
					paragraphCount = textToUse.Count();
					lastParagraphLength = paragraphCount == 0 ? 0 : textToUse[paragraphCount - 1].Length();
				});
			}

			void GuiDocumentCommonInterface::EditStyle(TextPos begin, TextPos end, Ptr<DocumentStyleProperties> style)
			{
				if (config.pasteAsPlainText) return;
				EditStyleInternal(begin, end, [=, this](TextPos begin, TextPos end)
				{
					documentElement->EditStyle(begin, end, style);
				});
			}

			void GuiDocumentCommonInterface::EditImage(TextPos begin, TextPos end, Ptr<GuiImageData> image)
			{
				if (config.pasteAsPlainText) return;
				EditTextInternal(begin, end, [=, this](TextPos begin, TextPos end, vint& paragraphCount, vint& lastParagraphLength)
				{
					documentElement->EditImage(begin, end, image);
					paragraphCount=1;
					lastParagraphLength=wcslen(DocumentImageRun::RepresentationText);
				});
			}

			void GuiDocumentCommonInterface::EditHyperlink(vint paragraphIndex, vint begin, vint end, const WString& reference, const WString& normalStyleName, const WString& activeStyleName)
			{
				if (config.pasteAsPlainText) return;
				EditStyleInternal(TextPos(paragraphIndex, begin), TextPos(paragraphIndex, end), [=, this](TextPos begin, TextPos end)
				{
					documentElement->EditHyperlink(begin.row, begin.column, end.column, reference, normalStyleName, activeStyleName);
				});
			}

			void GuiDocumentCommonInterface::RemoveHyperlink(vint paragraphIndex, vint begin, vint end)
			{
				if (config.pasteAsPlainText) return;
				EditStyleInternal(TextPos(paragraphIndex, begin), TextPos(paragraphIndex, end), [=, this](TextPos begin, TextPos end)
				{
					documentElement->RemoveHyperlink(begin.row, begin.column, end.column);
				});
			}

			void GuiDocumentCommonInterface::EditStyleName(TextPos begin, TextPos end, const WString& styleName)
			{
				if (config.pasteAsPlainText) return;
				EditStyleInternal(begin, end, [=, this](TextPos begin, TextPos end)
				{
					documentElement->EditStyleName(begin, end, styleName);
				});
			}

			void GuiDocumentCommonInterface::RemoveStyleName(TextPos begin, TextPos end)
			{
				if (config.pasteAsPlainText) return;
				EditStyleInternal(begin, end, [=, this](TextPos begin, TextPos end)
				{
					documentElement->RemoveStyleName(begin, end);
				});
			}

			void GuiDocumentCommonInterface::RenameStyle(const WString& oldStyleName, const WString& newStyleName)
			{
				if (config.pasteAsPlainText) return;
				documentElement->RenameStyle(oldStyleName, newStyleName);

				// submit redo-undo
				GuiDocumentUndoRedoProcessor::RenameStyleStruct arguments;
				arguments.oldStyleName=oldStyleName;
				arguments.newStyleName=newStyleName;
				undoRedoProcessor->OnRenameStyle(arguments);
			}

			void GuiDocumentCommonInterface::ClearStyle(TextPos begin, TextPos end)
			{
				if (config.pasteAsPlainText) return;
				EditStyleInternal(begin, end, [=, this](TextPos begin, TextPos end)
				{
					documentElement->ClearStyle(begin, end);
				});
			}

			void GuiDocumentCommonInterface::ConvertToPlainText(TextPos begin, TextPos end)
			{
				EditStyleInternal(begin, end, [=, this](TextPos begin, TextPos end)
				{
					documentElement->ConvertToPlainText(begin, end);
				});
			}

			Ptr<DocumentStyleProperties> GuiDocumentCommonInterface::SummarizeStyle(TextPos begin, TextPos end)
			{
				if (begin>end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}
				return documentElement->SummarizeStyle(begin, end);
			}

			Nullable<WString> GuiDocumentCommonInterface::SummarizeStyleName(TextPos begin, TextPos end)
			{
				if (begin>end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}
				return documentElement->SummarizeStyleName(begin, end);
			}

			void GuiDocumentCommonInterface::SetParagraphAlignments(TextPos begin, TextPos end, const collections::Array<Nullable<Alignment>>& alignments)
			{
				vint first = begin.row;
				vint last = end.row;
				if (first > last)
				{
					vint temp = first;
					first = last;
					last = temp;
				}

				Ptr<DocumentModel> document = documentElement->GetDocument();
				if (0 <= first && first < document->paragraphs.Count() && 0 <= last && last < document->paragraphs.Count() && last - first + 1 == alignments.Count())
				{
					auto arguments = Ptr(new GuiDocumentUndoRedoProcessor::SetAlignmentStruct);
					arguments->start = first;
					arguments->end = last;
					arguments->originalAlignments.Resize(alignments.Count());
					arguments->inputAlignments.Resize(alignments.Count());
					for (vint i = first; i <= last; i++)
					{
						arguments->originalAlignments[i - first] = document->paragraphs[i]->alignment;
						arguments->inputAlignments[i - first] = alignments[i - first];
					}
					documentElement->SetParagraphAlignment(begin, end, alignments);
					undoRedoProcessor->OnSetAlignment(arguments);
				}
			}

			void GuiDocumentCommonInterface::SetParagraphAlignment(TextPos begin, TextPos end, Nullable<Alignment> alignment)
			{
#if defined VCZH_GCC && defined VCZH_64
#define abs labs
#endif
				Array<Nullable<Alignment>> alignments(abs(begin.row - end.row) + 1);
#if defined VCZH_GCC && defined VCZH_64
#undef abs
#endif
				for (vint i = 0; i < alignments.Count(); i++)
				{
					alignments[i] = alignment;
				}
				SetParagraphAlignments(begin, end, alignments);
			}

			Nullable<Alignment> GuiDocumentCommonInterface::SummarizeParagraphAlignment(TextPos begin, TextPos end)
			{
				if (begin>end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}
				return documentElement->SummarizeParagraphAlignment(begin, end);
			}

			//================ editing control

			WString GuiDocumentCommonInterface::GetActiveHyperlinkReference()
			{
				return activeHyperlinks ? activeHyperlinks->hyperlinks[0]->reference : L"";
			}

			GuiDocumentEditMode GuiDocumentCommonInterface::GetEditMode()
			{
				return editMode;
			}

			void GuiDocumentCommonInterface::SetEditMode(GuiDocumentEditMode value)
			{
				if (activeHyperlinks)
				{
					SetActiveHyperlink(nullptr);
				}

				editMode = value;
				if (editMode == GuiDocumentEditMode::ViewOnly)
				{
					UpdateCursor(nullptr);
				}
				else
				{
					INativeCursor* cursor = GetCurrentController()->ResourceService()->GetSystemCursor(INativeCursor::IBeam);
					UpdateCursor(cursor);
				}
			}

			void GuiDocumentCommonInterface::LoadTextAndClearUndoRedo(const WString& text)
			{
				vint lastIndex = documentElement->GetDocument()->paragraphs.Count() - 1;
				Ptr<DocumentParagraphRun> lastParagraph = documentElement->GetDocument()->paragraphs[lastIndex];

				TextPos begin(0, 0);
				TextPos end(lastIndex, lastParagraph->GetTextForCaret().Length());

				List<WString> paragraphTexts;
				UserInput_FormatText(text, paragraphTexts, config);
				Array<WString> paragraphLines;
				CopyFrom(paragraphLines, paragraphTexts);

				EditTextInternal(begin, end, [=, this, &paragraphLines](TextPos begin, TextPos end, vint& paragraphCount, vint& lastParagraphLength)
				{
					documentElement->EditText(begin, end, true, paragraphLines);
					paragraphCount = paragraphLines.Count();
					lastParagraphLength = paragraphCount == 0 ? 0 : paragraphLines[paragraphCount - 1].Length();
				}, true);

				SetCaret(begin, begin);
				EnsureDocumentRectVisible(documentElement->GetCaretBounds(begin, true));
			}

			void GuiDocumentCommonInterface::LoadDocumentAndClearUndoRedo(Ptr<DocumentModel> document, bool copy)
			{
				vint lastIndex = documentElement->GetDocument()->paragraphs.Count() - 1;
				Ptr<DocumentParagraphRun> lastParagraph = documentElement->GetDocument()->paragraphs[lastIndex];

				TextPos begin(0, 0);
				TextPos end(lastIndex, lastParagraph->GetTextForCaret().Length());

				document = copy ? (document ? document->CopyDocument() : nullptr) : document;
				EditTextInternal(begin, end, [=, this](TextPos begin, TextPos end, vint& paragraphCount, vint& lastParagraphLength)
				{
					documentElement->EditRun(begin, end, document, false);
					paragraphCount = document->paragraphs.Count();
					lastParagraphLength = paragraphCount == 0 ? 0 : document->paragraphs[paragraphCount - 1]->GetTextForCaret().Length();
				}, true);

				SetCaret(begin, begin);
				EnsureDocumentRectVisible(documentElement->GetCaretBounds(begin, true));
			}

			//================ selection operations

			void GuiDocumentCommonInterface::SelectAll()
			{
				vint lastIndex = documentElement->GetDocument()->paragraphs.Count() - 1;
				Ptr<DocumentParagraphRun> lastParagraph = documentElement->GetDocument()->paragraphs[lastIndex];

				TextPos begin(0, 0);
				TextPos end(lastIndex, lastParagraph->GetTextForCaret().Length());
				SetCaret(begin, end);
			}

			WString GuiDocumentCommonInterface::GetSelectionText()
			{
				TextPos begin=documentElement->GetCaretBegin();
				TextPos end=documentElement->GetCaretEnd();
				if(begin>end)
				{
					TextPos temp=begin;
					begin=end;
					end=temp;
				}

				Ptr<DocumentModel> model=documentElement->GetDocument()->CopyDocument(begin, end, false);
				return UserInput_ConvertDocumentToText(model);
			}

			void GuiDocumentCommonInterface::SetSelectionText(const WString& value)
			{
				List<WString> paragraphTexts;
				UserInput_FormatText(value, paragraphTexts, config);

				TextPos begin = documentElement->GetCaretBegin();
				TextPos end = documentElement->GetCaretEnd();
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				Array<WString> text;
				CopyFrom(text, paragraphTexts);
				EditText(begin, end, documentElement->IsCaretEndPreferFrontSide(), text, true);
			}

			Ptr<DocumentModel> GuiDocumentCommonInterface::GetSelectionModel()
			{
				TextPos begin=documentElement->GetCaretBegin();
				TextPos end=documentElement->GetCaretEnd();
				if(begin>end)
				{
					TextPos temp=begin;
					begin=end;
					end=temp;
				}

				Ptr<DocumentModel> model=documentElement->GetDocument()->CopyDocument(begin, end, true);
				return model;
			}

			void GuiDocumentCommonInterface::SetSelectionModel(Ptr<DocumentModel> value)
			{
				value = value ? value->CopyDocument() : nullptr;
				UserInput_FormatDocument(value, baselineDocument, config);
				TextPos begin=documentElement->GetCaretBegin();
				TextPos end=documentElement->GetCaretEnd();
				if(begin>end)
				{
					TextPos temp=begin;
					begin=end;
					end=temp;
				}

				EditRun(begin, end, value, true, true);
			}

			//================ clipboard operations

			bool GuiDocumentCommonInterface::CanCut()
			{
				return editMode == GuiDocumentEditMode::Editable && documentElement->GetCaretBegin() != documentElement->GetCaretEnd();
			}

			bool GuiDocumentCommonInterface::CanCopy()
			{
				return documentElement->GetCaretBegin()!=documentElement->GetCaretEnd();
			}

			bool GuiDocumentCommonInterface::CanPaste()
			{
				if (editMode == GuiDocumentEditMode::Editable)
				{
					auto reader = GetCurrentController()->ClipboardService()->ReadClipboard();
					if (config.pasteAsPlainText)
					{
						return reader->ContainsText();
					}
					else
					{
						return reader->ContainsText() || reader->ContainsDocument() || reader->ContainsImage();
					}
				}
				return false;
			}

			bool GuiDocumentCommonInterface::Cut()
			{
				if (!CanCut())return false;
				auto writer = GetCurrentController()->ClipboardService()->WriteClipboard();
				auto model = GetSelectionModel();
				writer->SetText(UserInput_ConvertDocumentToText(model));
				if (!config.pasteAsPlainText)
				{
					writer->SetDocument(model);
				}
				writer->Submit();
				SetSelectionText(L"");
				return true;
			}

			bool GuiDocumentCommonInterface::Copy()
			{
				if (!CanCopy()) return false;
				auto writer = GetCurrentController()->ClipboardService()->WriteClipboard();
				auto model = GetSelectionModel();
				writer->SetText(UserInput_ConvertDocumentToText(model));
				if (!config.pasteAsPlainText)
				{
					writer->SetDocument(model);
				}
				writer->Submit();
				return true;
			}

			bool GuiDocumentCommonInterface::Paste()
			{
				if (!CanPaste()) return false;
				auto reader = GetCurrentController()->ClipboardService()->ReadClipboard();
				if (reader->ContainsDocument() && !config.pasteAsPlainText)
				{
					if (auto document = reader->GetDocument())
					{
						SetSelectionModel(document);
						return true;
					}
				}
				if (reader->ContainsText())
				{
					SetSelectionText(reader->GetText());
					return true;
				}
				if (reader->ContainsImage() && !config.pasteAsPlainText)
				{
					if (auto image = reader->GetImage())
					{
						auto imageData = Ptr(new GuiImageData(image, 0));
						EditImage(GetCaretBegin(), GetCaretEnd(), imageData);
						return true;
					}
				}
				return false;
			}

			//================ undo redo control

			bool GuiDocumentCommonInterface::CanUndo()
			{
				return editMode == GuiDocumentEditMode::Editable && undoRedoProcessor->CanUndo();
			}

			bool GuiDocumentCommonInterface::CanRedo()
			{
				return editMode == GuiDocumentEditMode::Editable && undoRedoProcessor->CanRedo();
			}

			void GuiDocumentCommonInterface::ClearUndoRedo()
			{
				undoRedoProcessor->ClearUndoRedo();
			}

			bool GuiDocumentCommonInterface::GetModified()
			{
				return undoRedoProcessor->GetModified();
			}

			void GuiDocumentCommonInterface::NotifyModificationSaved()
			{
				undoRedoProcessor->NotifyModificationSaved();
			}

			bool GuiDocumentCommonInterface::Undo()
			{
				if(CanUndo())
				{
					return undoRedoProcessor->Undo();
				}
				else
				{
					return false;
				}
			}

			bool GuiDocumentCommonInterface::Redo()
			{
				if(CanRedo())
				{
					return undoRedoProcessor->Redo();
				}
				else
				{
					return false;
				}
			}
		}
	}
}


/***********************************************************************
.\CONTROLS\TEXTEDITORPACKAGE\GUIDOCUMENTCONFIG.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
/***********************************************************************
GuiDocumentConfig
***********************************************************************/

			GuiDocumentConfig GuiDocumentConfig::GetDocumentLabelDefaultConfig()
			{
				GuiDocumentConfig config;
				config.autoExpand = true;
				config.pasteAsPlainText = false;
				config.wrapLine = true;
				config.paragraphMode = GuiDocumentParagraphMode::Paragraph;
				config.paragraphPadding = true;
				config.doubleLineBreaksBetweenParagraph = true;

				config.spaceForFlattenedLineBreak = false;
				config.paragraphRecycle = false;
				return config;
			}

			GuiDocumentConfig GuiDocumentConfig::GetDocumentViewerDefaultConfig()
			{
				GuiDocumentConfig config;
				config.autoExpand = false;
				config.pasteAsPlainText = false;
				config.wrapLine = true;
				config.paragraphMode = GuiDocumentParagraphMode::Paragraph;
				config.paragraphPadding = true;
				config.doubleLineBreaksBetweenParagraph = true;

				config.spaceForFlattenedLineBreak = false;
				config.paragraphRecycle = true;
				return config;
			}

			GuiDocumentConfig GuiDocumentConfig::GetSinglelineTextBoxDefaultConfig()
			{
				GuiDocumentConfig config;
				config.autoExpand = false;
				config.pasteAsPlainText = true;
				config.wrapLine = false;
				config.paragraphMode = GuiDocumentParagraphMode::Singleline;
				config.paragraphPadding = false;
				config.doubleLineBreaksBetweenParagraph = false;

				config.spaceForFlattenedLineBreak = false;
				config.paragraphRecycle = false;
				return config;
			}

			GuiDocumentConfig GuiDocumentConfig::GetMultilineTextBoxDefaultConfig()
			{
				GuiDocumentConfig config;
				config.autoExpand = false;
				config.pasteAsPlainText = true;
				config.wrapLine = false;
				config.paragraphMode = GuiDocumentParagraphMode::Multiline;
				config.paragraphPadding = false;
				config.doubleLineBreaksBetweenParagraph = false;

				config.spaceForFlattenedLineBreak = false;
				config.paragraphRecycle = true;
				return config;
			}

			GuiDocumentConfig GuiDocumentConfig::OverrideConfig(const GuiDocumentConfig& toOverride, const GuiDocumentConfig& newConfig)
			{
				GuiDocumentConfig result = toOverride;
				if (newConfig.autoExpand) result.autoExpand = newConfig.autoExpand;
				if (newConfig.pasteAsPlainText) result.pasteAsPlainText = newConfig.pasteAsPlainText;
				if (newConfig.wrapLine) result.wrapLine = newConfig.wrapLine;
				if (newConfig.paragraphMode) result.paragraphMode = newConfig.paragraphMode;
				if (newConfig.paragraphPadding) result.paragraphPadding = newConfig.paragraphPadding;
				if (newConfig.doubleLineBreaksBetweenParagraph) result.doubleLineBreaksBetweenParagraph = newConfig.doubleLineBreaksBetweenParagraph;
				if (newConfig.spaceForFlattenedLineBreak) result.spaceForFlattenedLineBreak = newConfig.spaceForFlattenedLineBreak;
				if (newConfig.paragraphRecycle) result.paragraphRecycle = newConfig.paragraphRecycle;
				return result;
			}

/***********************************************************************
GuiDocumentConfigEvaluated
***********************************************************************/

			GuiDocumentConfigEvaluated::GuiDocumentConfigEvaluated(const GuiDocumentConfig& config)
				: autoExpand(config.autoExpand.Value())
				, pasteAsPlainText(config.pasteAsPlainText.Value())
				, wrapLine(config.wrapLine.Value())
				, paragraphMode(config.paragraphMode.Value())
				, paragraphPadding(config.paragraphPadding.Value())
				, doubleLineBreaksBetweenParagraph(config.doubleLineBreaksBetweenParagraph.Value())
				, spaceForFlattenedLineBreak(config.spaceForFlattenedLineBreak.Value())
				, paragraphRecycle(config.paragraphRecycle.Value())
			{
			}
		}
	}
}


/***********************************************************************
.\CONTROLS\TEXTEDITORPACKAGE\GUIDOCUMENTVIEWER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace compositions;

/***********************************************************************
GuiDocumentViewer
***********************************************************************/

			void GuiDocumentViewer::BeforeControlTemplateUninstalled_()
			{
				ReplaceMouseArea(nullptr);
			}

			void GuiDocumentViewer::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				baselineDocument = ct->GetBaselineDocument();
				if (documentElement)
				{
					documentElement->SetCaretColor(ct->GetCaretColor());
					SetDocument(GetDocument());
				}
				ReplaceMouseArea(containerComposition->GetParent());
			}

			void GuiDocumentViewer::UpdateDisplayFont()
			{
				GuiScrollContainer::UpdateDisplayFont();
				OnFontChanged();
			}

			Point GuiDocumentViewer::GetDocumentViewPosition()
			{
				// the document does not move in containerComposition
				return { 0,0 };
			}

			void GuiDocumentViewer::EnsureRectVisible(Rect bounds)
			{
				Rect viewBounds=GetViewBounds();
				{
					vint offset = 0;
					if (bounds.x1 < viewBounds.x1)
					{
						offset = bounds.x1 - viewBounds.x1;
					}
					else if (bounds.x2 > viewBounds.x2)
					{
						offset = bounds.x2 - viewBounds.x2;
					}

					if (auto scroll = GetHorizontalScroll())
					{
						scroll->SetPosition(viewBounds.x1 + offset);
					}
				}
				{
					vint offset = 0;
					if (bounds.y1 < viewBounds.y1)
					{
						offset = bounds.y1 - viewBounds.y1;
					}
					else if (bounds.y2 > viewBounds.y2)
					{
						offset = bounds.y2 - viewBounds.y2;
					}

					if (auto scroll = GetVerticalScroll())
					{
						scroll->SetPosition(viewBounds.y1 + offset);
					}
				}
			}

			GuiDocumentConfig GuiDocumentViewer::FixConfig(const GuiDocumentConfig& config)
			{
				auto result = config;
				result.autoExpand = false;
				return config;
			}

			GuiDocumentViewer::GuiDocumentViewer(theme::ThemeName themeName, const GuiDocumentConfig& _config)
				: GuiScrollContainer(themeName)
				, GuiDocumentCommonInterface(FixConfig(GuiDocumentConfig::OverrideConfig(GuiDocumentConfig::GetDocumentViewerDefaultConfig(), _config)))
			{
				SetAcceptTabInput(true);
				SetFocusableComposition(boundsComposition);
				InstallDocumentViewer(this, containerComposition->GetParent(), containerComposition, boundsComposition, focusableComposition);

				SetExtendToFullWidth(config.wrapLine);
				SetHorizontalAlwaysVisible(!config.wrapLine);
			}

			GuiDocumentViewer::~GuiDocumentViewer()
			{
			}

			const WString& GuiDocumentViewer::GetText()
			{
				text = UserInput_ConvertDocumentToText(documentElement->GetDocument());
				return text;
			}

			void GuiDocumentViewer::SetText(const WString& value)
			{
				SelectAll();
				SetSelectionText(value);
			}

/***********************************************************************
GuiMultilineTextBox
***********************************************************************/

			GuiMultilineTextBox::GuiMultilineTextBox(theme::ThemeName themeName, const GuiDocumentConfig& _config)
				: GuiDocumentViewer(themeName, FixConfig(GuiDocumentConfig::OverrideConfig(GuiDocumentConfig::GetMultilineTextBoxDefaultConfig(), _config)))
			{
				SetEditMode(GuiDocumentEditMode::Editable);
			}

			GuiMultilineTextBox::~GuiMultilineTextBox()
			{
			}

/***********************************************************************
GuiDocumentLabel
***********************************************************************/

			void GuiDocumentLabel::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiDocumentLabel::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				baselineDocument = ct->GetBaselineDocument();
				if (documentElement)
				{
					documentElement->SetCaretColor(ct->GetCaretColor());
					SetDocument(GetDocument());
				}
			}

			void GuiDocumentLabel::UpdateDisplayFont()
			{
				GuiControl::UpdateDisplayFont();
				OnFontChanged();
			}

			Point GuiDocumentLabel::GetDocumentViewPosition()
			{
				// when autoExpand is true, the document does not move in containerComposition
				// when autoExpand is not false, the document does not move in documentContainer
				return{ 0,0 };
			}

			void GuiDocumentLabel::EnsureRectVisible(Rect bounds)
			{
				if (!scrollingContainer) return;
				vint documentWidth = documentContainer->GetCachedBounds().Width();
				vint scrollingWidth = scrollingContainer->GetCachedBounds().Width();
				if (documentWidth <= scrollingWidth)
				{
					documentContainer->SetExpectedBounds({});
					return;
				}

				vint x1 = -documentContainer->GetCachedBounds().x1;
				vint x2 = x1 + scrollingWidth;
				vint offset = 0;

				if (bounds.x1 < x1)
				{
					offset = bounds.x1 - x1;
				}
				else if (bounds.x2 > x2)
				{
					offset = bounds.x2 - x2;
				}

				auto expectedBounds = documentContainer->GetExpectedBounds();
				expectedBounds.x1 -= offset;
				expectedBounds.x2 -= offset;

				if (expectedBounds.x1 > 0)
				{
					expectedBounds.x1 = 0;
				}
				else if (expectedBounds.x1 + documentWidth < scrollingWidth)
				{
					expectedBounds.x1 = scrollingWidth - documentWidth;
				}
				expectedBounds.x2 = expectedBounds.x1;
				documentContainer->SetExpectedBounds(expectedBounds);
				documentContainer->ForceCalculateSizeImmediately();
			}

			void GuiDocumentLabel::scrollingContainer_CachedBoundsChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				Rect bounds = scrollingContainer->GetCachedBounds();
				vint x1 = documentContainer->GetCachedBounds().x1;
				vint offset = -x1 - bounds.x1;
				bounds.x1 += offset;
				bounds.x2 += offset;
				EnsureRectVisible(bounds);
			}

			void GuiDocumentLabel::documentContainer_CachedMinSizeChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				scrollingContainer->SetPreferredMinSize({ 0,documentContainer->GetCachedMinSize().y });
			}

			GuiDocumentConfig GuiDocumentLabel::FixConfig(const GuiDocumentConfig& config)
			{
				auto result = config;
				if (!result.autoExpand.Value())
				{
					if (result.wrapLine.Value() || result.paragraphMode.Value() != GuiDocumentParagraphMode::Singleline)
					{
						result.autoExpand = true;
					}
				}
				return result;
			}

			GuiDocumentLabel::GuiDocumentLabel(theme::ThemeName themeName, const GuiDocumentConfig& _config)
				: GuiControl(themeName)
				, GuiDocumentCommonInterface(FixConfig(GuiDocumentConfig::OverrideConfig(GuiDocumentConfig::GetDocumentLabelDefaultConfig(), _config)))
			{
				SetAcceptTabInput(true);
				SetFocusableComposition(boundsComposition);

				if (config.autoExpand)
				{
					InstallDocumentViewer(this, containerComposition, containerComposition, boundsComposition, focusableComposition);
				}
				else
				{
					scrollingContainer = new GuiBoundsComposition();
					scrollingContainer->SetAlignmentToParent(Margin(0, 0, 0, 0));
					containerComposition->AddChild(scrollingContainer);

					documentContainer = new GuiBoundsComposition();
					documentContainer->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					scrollingContainer->AddChild(documentContainer);

					scrollingContainer->CachedBoundsChanged.AttachMethod(this, &GuiDocumentLabel::scrollingContainer_CachedBoundsChanged);
					documentContainer->CachedBoundsChanged.AttachMethod(this, &GuiDocumentLabel::documentContainer_CachedMinSizeChanged);
					InstallDocumentViewer(this, containerComposition, documentContainer, boundsComposition, focusableComposition);
				}
			}

			GuiDocumentLabel::~GuiDocumentLabel()
			{
			}

			const WString& GuiDocumentLabel::GetText()
			{
				text = UserInput_ConvertDocumentToText(documentElement->GetDocument());
				return text;
			}

			void GuiDocumentLabel::SetText(const WString& value)
			{
				SelectAll();
				SetSelectionText(value);
			}

/***********************************************************************
GuiSinglelineTextBox
***********************************************************************/

			GuiSinglelineTextBox::GuiSinglelineTextBox(theme::ThemeName themeName, const GuiDocumentConfig& _config)
				: GuiDocumentLabel(themeName, FixConfig(GuiDocumentConfig::OverrideConfig(GuiDocumentConfig::GetSinglelineTextBoxDefaultConfig(), _config)))
			{
				SetEditMode(GuiDocumentEditMode::Editable);
			}

			GuiSinglelineTextBox::~GuiSinglelineTextBox()
			{
			}

			wchar_t GuiSinglelineTextBox::GetPasswordChar()
			{
				return documentElement->GetPasswordChar();
			}

			void GuiSinglelineTextBox::SetPasswordChar(wchar_t value)
			{
				documentElement->SetPasswordChar(value);
			}
		}
	}
}


/***********************************************************************
.\CONTROLS\TEXTEDITORPACKAGE\EDITORCALLBACK\GUITEXTUNDOREDO.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace elements;
			using namespace compositions;

/***********************************************************************
GuiGeneralUndoRedoProcessor
***********************************************************************/

			GuiGeneralUndoRedoProcessor::GuiGeneralUndoRedoProcessor()
				:firstFutureStep(0)
				,savedStep(0)
				,performingUndoRedo(false)
			{
			}

			GuiGeneralUndoRedoProcessor::~GuiGeneralUndoRedoProcessor()
			{
			}

			void GuiGeneralUndoRedoProcessor::PushStep(Ptr<IEditStep> step)
			{
				if(!performingUndoRedo)
				{
					if(firstFutureStep<savedStep)
					{
						savedStep=-1;
					}

					vint count=steps.Count()-firstFutureStep;
					if(count>0)
					{
						steps.RemoveRange(firstFutureStep, count);
					}
				
					steps.Add(step);
					firstFutureStep=steps.Count();
					UndoRedoChanged();
					ModifiedChanged();
				}
			}

			bool GuiGeneralUndoRedoProcessor::CanUndo()
			{
				return firstFutureStep>0;
			}

			bool GuiGeneralUndoRedoProcessor::CanRedo()
			{
				return steps.Count()>firstFutureStep;
			}

			void GuiGeneralUndoRedoProcessor::ClearUndoRedo()
			{
				if(!performingUndoRedo)
				{
					steps.Clear();
					firstFutureStep=0;
					savedStep=0;
				}
			}

			bool GuiGeneralUndoRedoProcessor::GetModified()
			{
				return firstFutureStep!=savedStep;
			}

			void GuiGeneralUndoRedoProcessor::NotifyModificationSaved()
			{
				if(!performingUndoRedo)
				{
					savedStep=firstFutureStep;
					ModifiedChanged();
				}
			}

			bool GuiGeneralUndoRedoProcessor::Undo()
			{
				if(!CanUndo()) return false;
				performingUndoRedo=true;
				firstFutureStep--;
				steps[firstFutureStep]->Undo();
				performingUndoRedo=false;
				UndoRedoChanged();
				ModifiedChanged();
				return true;
			}

			bool GuiGeneralUndoRedoProcessor::Redo()
			{
				if(!CanRedo()) return false;
				performingUndoRedo=true;
				firstFutureStep++;
				steps[firstFutureStep-1]->Redo();
				performingUndoRedo=false;
				UndoRedoChanged();
				ModifiedChanged();
				return true;
			}

/***********************************************************************
GuiDocumentUndoRedoProcessor::ReplaceModelStep
***********************************************************************/

			void GuiDocumentUndoRedoProcessor::ReplaceModelStep::Undo()
			{
				GuiDocumentCommonInterface* ci=dynamic_cast<GuiDocumentCommonInterface*>(processor->ownerComposition->GetRelatedControl());
				if(ci)
				{
					ci->EditRun(arguments.inputStart, arguments.inputEnd, arguments.originalModel, true);
					ci->SetCaret(arguments.originalStart, arguments.originalEnd);
				}
			}

			void GuiDocumentUndoRedoProcessor::ReplaceModelStep::Redo()
			{
				GuiDocumentCommonInterface* ci=dynamic_cast<GuiDocumentCommonInterface*>(processor->ownerComposition->GetRelatedControl());
				if(ci)
				{
					ci->EditRun(arguments.originalStart, arguments.originalEnd, arguments.inputModel, true);
					ci->SetCaret(arguments.inputStart, arguments.inputEnd);
				}
			}

/***********************************************************************
GuiDocumentUndoRedoProcessor::RenameStyleStep
***********************************************************************/

			void GuiDocumentUndoRedoProcessor::RenameStyleStep::Undo()
			{
				GuiDocumentCommonInterface* ci=dynamic_cast<GuiDocumentCommonInterface*>(processor->ownerComposition->GetRelatedControl());
				if(ci)
				{
					ci->RenameStyle(arguments.newStyleName, arguments.oldStyleName);
				}
			}

			void GuiDocumentUndoRedoProcessor::RenameStyleStep::Redo()
			{
				GuiDocumentCommonInterface* ci=dynamic_cast<GuiDocumentCommonInterface*>(processor->ownerComposition->GetRelatedControl());
				if(ci)
				{
					ci->RenameStyle(arguments.oldStyleName, arguments.newStyleName);
				}
			}

/***********************************************************************
GuiDocumentUndoRedoProcessor::SetAlignmentStep
***********************************************************************/

			void GuiDocumentUndoRedoProcessor::SetAlignmentStep::Undo()
			{
				GuiDocumentCommonInterface* ci=dynamic_cast<GuiDocumentCommonInterface*>(processor->ownerComposition->GetRelatedControl());
				if(ci)
				{
					ci->SetParagraphAlignments(TextPos(arguments->start, 0), TextPos(arguments->end, 0), arguments->originalAlignments);
				}
			}

			void GuiDocumentUndoRedoProcessor::SetAlignmentStep::Redo()
			{
				GuiDocumentCommonInterface* ci=dynamic_cast<GuiDocumentCommonInterface*>(processor->ownerComposition->GetRelatedControl());
				if(ci)
				{
					ci->SetParagraphAlignments(TextPos(arguments->start, 0), TextPos(arguments->end, 0), arguments->inputAlignments);
				}
			}

/***********************************************************************
GuiDocumentUndoRedoProcessor
***********************************************************************/

			GuiDocumentUndoRedoProcessor::GuiDocumentUndoRedoProcessor()
				:element(0)
				,ownerComposition(0)
			{
			}

			GuiDocumentUndoRedoProcessor::~GuiDocumentUndoRedoProcessor()
			{
			}

			void GuiDocumentUndoRedoProcessor::Setup(elements::GuiDocumentElement* _element, compositions::GuiGraphicsComposition* _ownerComposition)
			{
				element=_element;
				ownerComposition=_ownerComposition;
			}

			void GuiDocumentUndoRedoProcessor::OnReplaceModel(const ReplaceModelStruct& arguments)
			{
				auto step=Ptr(new ReplaceModelStep);
				step->processor=this;
				step->arguments=arguments;
				PushStep(step);
			}

			void GuiDocumentUndoRedoProcessor::OnRenameStyle(const RenameStyleStruct& arguments)
			{
				auto step=Ptr(new RenameStyleStep);
				step->processor=this;
				step->arguments=arguments;
				PushStep(step);
			}

			void GuiDocumentUndoRedoProcessor::OnSetAlignment(Ptr<SetAlignmentStruct> arguments)
			{
				auto step=Ptr(new SetAlignmentStep);
				step->processor=this;
				step->arguments=arguments;
				PushStep(step);
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\TOOLSTRIPPACKAGE\GUIMENUCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace compositions;

/***********************************************************************
IGuiMenuService
***********************************************************************/

			const wchar_t* const IGuiMenuService::Identifier = L"vl::presentation::controls::IGuiMenuService";
			const wchar_t* const IGuiMenuDropdownProvider::Identifier = L"vl::presentation::controls::IGuiMenuDropdownProvider";

			IGuiMenuService::IGuiMenuService()
				:openingMenu(0)
			{
			}

			void IGuiMenuService::MenuItemExecuted()
			{
				if(openingMenu)
				{
					openingMenu->Hide();
				}
				if(GetParentMenuService())
				{
					GetParentMenuService()->MenuItemExecuted();
				}
			}

			GuiMenu* IGuiMenuService::GetOpeningMenu()
			{
				return openingMenu;
			}

			void IGuiMenuService::MenuOpened(GuiMenu* menu)
			{
				if(openingMenu!=menu && openingMenu)
				{
					openingMenu->Hide();
				}
				openingMenu=menu;
			}

			void IGuiMenuService::MenuClosed(GuiMenu* menu)
			{
				if(openingMenu==menu)
				{
					openingMenu=0;
				}
			}

/***********************************************************************
GuiMenu
***********************************************************************/

			void GuiMenu::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiMenu::AfterControlTemplateInstalled_(bool initialize)
			{
			}

			IGuiMenuService* GuiMenu::GetParentMenuService()
			{
				return parentMenuService;
			}

			IGuiMenuService::Direction GuiMenu::GetPreferredDirection()
			{
				return IGuiMenuService::Vertical;
			}

			theme::ThemeName GuiMenu::GetHostThemeName()
			{
				return GetControlThemeName();
			}

			bool GuiMenu::IsActiveState()
			{
				return true;
			}

			bool GuiMenu::IsSubMenuActivatedByMouseDown()
			{
				return false;
			}

			void GuiMenu::MenuItemExecuted()
			{
				IGuiMenuService::MenuItemExecuted();
				Hide();
			}

			void GuiMenu::Moving(NativeRect& bounds, bool fixSizeOnly, bool draggingBorder)
			{
				GuiPopup::Moving(bounds, fixSizeOnly, draggingBorder);
				if (draggingBorder)
				{
					if (auto nativeWindow = GetNativeWindow())
					{
						auto newSize = bounds.GetSize();
						auto nativeOffset = (nativeWindow->GetBounds().GetSize() - nativeWindow->GetClientSize());
						auto preferredNativeSize = nativeWindow->Convert(preferredMenuClientSizeBeforeUpdating) + nativeOffset;
						if (newSize.x < preferredNativeSize.x) newSize.x = preferredNativeSize.x;
						if (newSize.y < preferredNativeSize.y) newSize.y = preferredNativeSize.y;
						preferredMenuClientSize = nativeWindow->Convert(newSize - nativeOffset);
					}
				}
			}

			void GuiMenu::UpdateClientSizeAfterRendering(Size preferredSize, Size clientSize)
			{
				auto size = preferredSize;
				if (size.x < preferredMenuClientSize.x) size.x = preferredMenuClientSize.x;
				if (size.y < preferredMenuClientSize.y) size.y = preferredMenuClientSize.y;
				GuiPopup::UpdateClientSizeAfterRendering(preferredSize, size);
			}

			void GuiMenu::OnWindowOpened(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if(parentMenuService)
				{
					parentMenuService->MenuOpened(this);
				}
			}

			void GuiMenu::OnDeactivatedAltHost()
			{
				if(hideOnDeactivateAltHost)
				{
					Hide();
				}
				GuiPopup::OnDeactivatedAltHost();
			}

			void GuiMenu::OnWindowClosed(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if(parentMenuService)
				{
					parentMenuService->MenuClosed(this);
					GuiMenu* openingSubMenu=GetOpeningMenu();
					if(openingSubMenu)
					{
						openingSubMenu->Hide();
					}
				}
			}

			GuiMenu::GuiMenu(theme::ThemeName themeName, GuiControl* _owner)
				:GuiPopup(themeName, INativeWindow::Menu)
				, owner(_owner)
			{
				UpdateMenuService();
				WindowOpened.AttachMethod(this, &GuiMenu::OnWindowOpened);
				WindowClosed.AttachMethod(this, &GuiMenu::OnWindowClosed);
			}

			GuiMenu::~GuiMenu()
			{
			}

			void GuiMenu::UpdateMenuService()
			{
				if(owner)
				{
					parentMenuService=owner->QueryTypedService<IGuiMenuService>();
				}
			}

			IDescriptable* GuiMenu::QueryService(const WString& identifier)
			{
				if(identifier==IGuiMenuService::Identifier)
				{
					return (IGuiMenuService*)this;
				}
				else
				{
					return GuiPopup::QueryService(identifier);
				}
			}
			
			bool GuiMenu::GetHideOnDeactivateAltHost()
			{
				return hideOnDeactivateAltHost;
			}

			void GuiMenu::SetHideOnDeactivateAltHost(bool value)
			{
				hideOnDeactivateAltHost = value;
			}

			Size GuiMenu::GetPreferredMenuClientSize()
			{
				return preferredMenuClientSize;
			}

			void GuiMenu::SetPreferredMenuClientSize(Size value)
			{
				preferredMenuClientSize = value;
				preferredMenuClientSizeBeforeUpdating = value;
			}

/***********************************************************************
GuiMenuBar
***********************************************************************/

			IGuiMenuService* GuiMenuBar::GetParentMenuService()
			{
				return GetParent() ? GetParent()->QueryTypedService<IGuiMenuService>() : nullptr;
			}

			IGuiMenuService::Direction GuiMenuBar::GetPreferredDirection()
			{
				return IGuiMenuService::Horizontal;
			}

			theme::ThemeName GuiMenuBar::GetHostThemeName()
			{
				return GetControlThemeName();
			}

			bool GuiMenuBar::IsActiveState()
			{
				return GetOpeningMenu()!=0;
			}

			bool GuiMenuBar::IsSubMenuActivatedByMouseDown()
			{
				return true;
			}

			GuiMenuBar::GuiMenuBar(theme::ThemeName themeName)
				:GuiControl(themeName)
			{
			}

			GuiMenuBar::~GuiMenuBar()
			{
			}

			IDescriptable* GuiMenuBar::QueryService(const WString& identifier)
			{
				if(identifier==IGuiMenuService::Identifier)
				{
					return (IGuiMenuService*)this;
				}
				else
				{
					return GuiControl::QueryService(identifier);
				}
			}

/***********************************************************************
GuiMenuButton
***********************************************************************/

			void GuiMenuButton::BeforeControlTemplateUninstalled_()
			{
				auto host = GetSubMenuHost();
				host->Clicked.Detach(hostClickedHandler);
				host->GetBoundsComposition()->GetEventReceiver()->mouseEnter.Detach(hostMouseEnterHandler);

				hostClickedHandler = nullptr;
				hostMouseEnterHandler = nullptr;
			}

			void GuiMenuButton::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				auto host = GetSubMenuHost();

				ct->SetSubMenuOpening(GetSubMenuOpening());
				ct->SetLargeImage(largeImage);
				ct->SetImage(image);
				ct->SetShortcutText(shortcutText);
				ct->SetSubMenuExisting(subMenu != nullptr);

				hostClickedHandler = host->BeforeClicked.AttachMethod(this, &GuiMenuButton::OnBeforeClicked);
				hostMouseEnterHandler = host->GetBoundsComposition()->GetEventReceiver()->mouseEnter.AttachMethod(this, &GuiMenuButton::OnMouseEnter);
			}

			bool GuiMenuButton::OpenSubMenuInternal()
			{
				if (!GetSubMenuOpening())
				{
					if (ownerMenuService)
					{
						GuiMenu* openingSiblingMenu = ownerMenuService->GetOpeningMenu();
						if (openingSiblingMenu)
						{
							openingSiblingMenu->Hide();
						}
					}

					BeforeSubMenuOpening.Execute(GetNotifyEventArguments());
					if (subMenu)
					{
						subMenu->SetClientSize(preferredMenuClientSize);
						IGuiMenuService::Direction direction = GetSubMenuDirection();
						subMenu->ShowPopup(GetSubMenuHost(), direction == IGuiMenuService::Horizontal);
						AfterSubMenuOpening.Execute(GetNotifyEventArguments());
						return true;
					}
				}
				return false;
			}

			void GuiMenuButton::OnParentLineChanged()
			{
				GuiButton::OnParentLineChanged();
				ownerMenuService=QueryTypedService<IGuiMenuService>();
				if(ownerMenuService)
				{
					SetClickOnMouseUp(!ownerMenuService->IsSubMenuActivatedByMouseDown());
				}
				if(subMenu)
				{
					subMenu->UpdateMenuService();
				}
			}

			compositions::IGuiAltActionHost* GuiMenuButton::GetActivatingAltHost()
			{
				if (subMenu)
				{
					return subMenu->QueryTypedService<IGuiAltActionHost>();
				}
				else
				{
					return GuiSelectableButton::GetActivatingAltHost();
				}
			}

			void GuiMenuButton::OnSubMenuWindowOpened(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				TypedControlTemplateObject(true)->SetSubMenuOpening(true);
				SubMenuOpeningChanged.Execute(GetNotifyEventArguments());
			}

			void GuiMenuButton::OnSubMenuWindowClosed(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				TypedControlTemplateObject(true)->SetSubMenuOpening(false);
				SubMenuOpeningChanged.Execute(GetNotifyEventArguments());
			}

			void GuiMenuButton::OnMouseEnter(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if(GetVisuallyEnabled())
				{
					if(cascadeAction && ownerMenuService && ownerMenuService->IsActiveState())
					{
						OpenSubMenuInternal();
					}
				}
			}

			void GuiMenuButton::OnBeforeClicked(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if(GetVisuallyEnabled())
				{
					if(!OpenSubMenuInternal() && ownerMenuService)
					{
						ownerMenuService->MenuItemExecuted();
					}
				}
			}

			IGuiMenuService::Direction GuiMenuButton::GetSubMenuDirection()
			{
				return ownerMenuService?ownerMenuService->GetPreferredDirection():IGuiMenuService::Horizontal;
			}

			void GuiMenuButton::DetachSubMenu()
			{
				if (subMenu)
				{
					subMenu->WindowOpened.Detach(subMenuWindowOpenedHandler);
					subMenu->WindowClosed.Detach(subMenuWindowClosedHandler);

					subMenuWindowOpenedHandler = nullptr;
					subMenuWindowClosedHandler = nullptr;
					if (ownedSubMenu)
					{
						delete subMenu;
					}
				}
			}

			GuiMenu* GuiMenuButton::ProvideDropdownMenu()
			{
				return GetSubMenu();
			}

			GuiMenuButton::GuiMenuButton(theme::ThemeName themeName)
				:GuiSelectableButton(themeName)
				,subMenu(0)
				,ownedSubMenu(false)
				,ownerMenuService(0)
				,cascadeAction(true)
			{
				SetAutoSelection(false);
				BeforeSubMenuOpening.SetAssociatedComposition(boundsComposition);
				SubMenuOpeningChanged.SetAssociatedComposition(boundsComposition);
				LargeImageChanged.SetAssociatedComposition(boundsComposition);
				ImageChanged.SetAssociatedComposition(boundsComposition);
				ShortcutTextChanged.SetAssociatedComposition(boundsComposition);
			}

			GuiMenuButton::~GuiMenuButton()
			{
				if (!subMenuDisposeFlag || !subMenuDisposeFlag->IsDisposed())
				{
					DetachSubMenu();
				}
			}

			GuiButton* GuiMenuButton::GetSubMenuHost()
			{
				GuiButton* button = TypedControlTemplateObject(true)->GetSubMenuHost();
				return button ? button : this;
			}

			Ptr<GuiImageData> GuiMenuButton::GetLargeImage()
			{
				return largeImage;
			}

			void GuiMenuButton::SetLargeImage(Ptr<GuiImageData> value)
			{
				if (largeImage != value)
				{
					largeImage = value;
					TypedControlTemplateObject(true)->SetLargeImage(largeImage);
					LargeImageChanged.Execute(GetNotifyEventArguments());
				}
			}

			Ptr<GuiImageData> GuiMenuButton::GetImage()
			{
				return image;
			}

			void GuiMenuButton::SetImage(Ptr<GuiImageData> value)
			{
				if (image != value)
				{
					image = value;
					TypedControlTemplateObject(true)->SetImage(image);
					ImageChanged.Execute(GetNotifyEventArguments());
				}
			}

			const WString& GuiMenuButton::GetShortcutText()
			{
				return shortcutText;
			}

			void GuiMenuButton::SetShortcutText(const WString& value)
			{
				if (shortcutText != value)
				{
					shortcutText = value;
					TypedControlTemplateObject(true)->SetShortcutText(shortcutText);
					ShortcutTextChanged.Execute(GetNotifyEventArguments());
				}
			}

			bool GuiMenuButton::IsSubMenuExists()
			{
				return subMenu!=0;
			}

			GuiMenu* GuiMenuButton::GetSubMenu()
			{
				return subMenu;
			}

			GuiMenu* GuiMenuButton::CreateSubMenu(TemplateProperty<templates::GuiMenuTemplate> subMenuTemplate)
			{
				if (!subMenu)
				{
					GuiMenu* newSubMenu = new GuiMenu(theme::ThemeName::Menu, this);
					newSubMenu->SetControlTemplate(subMenuTemplate ? subMenuTemplate : TypedControlTemplateObject(true)->GetSubMenuTemplate());
					SetSubMenu(newSubMenu, true);
				}
				return subMenu;
			}

			void GuiMenuButton::SetSubMenu(GuiMenu* value, bool owned)
			{
				if (subMenu)
				{
					DetachSubMenu();
					subMenuDisposeFlag = nullptr;
				}
				subMenu = value;
				ownedSubMenu = owned;
				if (subMenu)
				{
					subMenu->SetPreferredMenuClientSize(preferredMenuClientSize);
					subMenuDisposeFlag = subMenu->GetDisposedFlag();
					subMenuWindowOpenedHandler = subMenu->WindowOpened.AttachMethod(this, &GuiMenuButton::OnSubMenuWindowOpened);
					subMenuWindowClosedHandler = subMenu->WindowClosed.AttachMethod(this, &GuiMenuButton::OnSubMenuWindowClosed);
				}
				TypedControlTemplateObject(true)->SetSubMenuExisting(subMenu != nullptr);
			}

			void GuiMenuButton::DestroySubMenu()
			{
				if(subMenu)
				{
					DetachSubMenu();
					subMenu=0;
					ownedSubMenu=false;
					TypedControlTemplateObject(true)->SetSubMenuExisting(false);
				}
			}

			bool GuiMenuButton::GetOwnedSubMenu()
			{
				return subMenu && ownedSubMenu;
			}

			bool GuiMenuButton::GetSubMenuOpening()
			{
				if(subMenu)
				{
					return subMenu->GetOpening();
				}
				else
				{
					return false;
				}
			}

			void GuiMenuButton::SetSubMenuOpening(bool value)
			{
				if (subMenu && subMenu->GetOpening() != value)
				{
					if (value)
					{
						OpenSubMenuInternal();
					}
					else
					{
						subMenu->Close();
					}
				}
			}

			Size GuiMenuButton::GetPreferredMenuClientSize()
			{
				return preferredMenuClientSize;
			}

			void GuiMenuButton::SetPreferredMenuClientSize(Size value)
			{
				preferredMenuClientSize = value;
				if (subMenu)
				{
					subMenu->SetPreferredMenuClientSize(preferredMenuClientSize);
				}
			}

			bool GuiMenuButton::GetCascadeAction()
			{
				return cascadeAction;
			}

			void GuiMenuButton::SetCascadeAction(bool value)
			{
				cascadeAction=value;
			}

			IDescriptable* GuiMenuButton::QueryService(const WString& identifier)
			{
				if (identifier == IGuiMenuDropdownProvider::Identifier)
				{
					return (IGuiMenuDropdownProvider*)this;
				}
				else
				{
					return GuiSelectableButton::QueryService(identifier);
				}
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\TOOLSTRIPPACKAGE\GUIRIBBONCONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace reflection::description;
			using namespace collections;
			using namespace compositions;
			using namespace theme;
			using namespace templates;

/***********************************************************************
GuiRibbonTab
***********************************************************************/

			void GuiRibbonTab::BeforeControlTemplateUninstalled_()
			{
				auto ct = TypedControlTemplateObject(false);
				if (!ct) return;

				if (auto bhc = ct->GetBeforeHeadersContainer())
				{
					bhc->RemoveChild(beforeHeaders);
				}
				if (auto ahc = ct->GetAfterHeadersContainer())
				{
					ahc->RemoveChild(afterHeaders);
				}
			}

			void GuiRibbonTab::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				if (auto bhc = ct->GetBeforeHeadersContainer())
				{
					bhc->AddChild(beforeHeaders);
				}
				if (auto ahc = ct->GetAfterHeadersContainer())
				{
					ahc->AddChild(afterHeaders);
				}
			}

			GuiRibbonTab::GuiRibbonTab(theme::ThemeName themeName)
				:GuiTab(themeName)
			{
				beforeHeaders = new GuiBoundsComposition();
				beforeHeaders->SetAlignmentToParent(Margin(0, 0, 0, 0));
				beforeHeaders->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

				afterHeaders = new GuiBoundsComposition();
				afterHeaders->SetAlignmentToParent(Margin(0, 0, 0, 0));
				afterHeaders->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
			}

			GuiRibbonTab::~GuiRibbonTab()
			{
				if (!beforeHeaders->GetParent())
				{
					SafeDeleteComposition(beforeHeaders);
				}
				if (!afterHeaders->GetParent())
				{
					SafeDeleteComposition(afterHeaders);
				}
			}

			compositions::GuiGraphicsComposition* GuiRibbonTab::GetBeforeHeaders()
			{
				return beforeHeaders;
			}

			compositions::GuiGraphicsComposition* GuiRibbonTab::GetAfterHeaders()
			{
				return afterHeaders;
			}

/***********************************************************************
GuiRibbonGroupCollection
***********************************************************************/

			bool GuiRibbonGroupCollection::QueryInsert(vint index, GuiRibbonGroup* const& value)
			{
				return !value->GetBoundsComposition()->GetParent();
			}

			void GuiRibbonGroupCollection::AfterInsert(vint index, GuiRibbonGroup* const& value)
			{
				value->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));

				auto item = new GuiStackItemComposition();
				item->AddChild(value->GetBoundsComposition());

				tabPage->stack->InsertStackItem(index, item);
			}

			void GuiRibbonGroupCollection::AfterRemove(vint index, vint count)
			{
				for (vint i = 0; i < count; i++)
				{
					auto item = tabPage->stack->GetStackItems()[index];
					tabPage->stack->RemoveChild(item);

					item->RemoveChild(item->Children()[0]);
					delete item;
				}
			}

			GuiRibbonGroupCollection::GuiRibbonGroupCollection(GuiRibbonTabPage* _tabPage)
				:tabPage(_tabPage)
			{
			}

			GuiRibbonGroupCollection::~GuiRibbonGroupCollection()
			{
			}

/***********************************************************************
GuiRibbonTabPage
***********************************************************************/

			GuiRibbonTabPage::GuiRibbonTabPage(theme::ThemeName themeName)
				:GuiTabPage(themeName)
				, groups(this)
			{
				stack = new GuiStackComposition();
				stack->SetDirection(GuiStackComposition::Horizontal);
				stack->SetAlignmentToParent(Margin(2, 2, 2, 2));
				stack->SetPadding(2);
				stack->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

				responsiveStack = new GuiResponsiveStackComposition();
				responsiveStack->SetDirection(ResponsiveDirection::Horizontal);
				responsiveStack->SetAlignmentToParent(Margin(0, 0, 0, 0));
				responsiveStack->AddChild(stack);

				responsiveContainer = new GuiResponsiveContainerComposition();
				responsiveContainer->SetAlignmentToParent(Margin(0, 0, 0, 0));
				responsiveContainer->SetResponsiveTarget(responsiveStack);

				containerComposition->AddChild(responsiveContainer);

				HighlightedChanged.SetAssociatedComposition(boundsComposition);
			}

			GuiRibbonTabPage::~GuiRibbonTabPage()
			{
			}

			bool GuiRibbonTabPage::GetHighlighted()
			{
				return highlighted;
			}

			void GuiRibbonTabPage::SetHighlighted(bool value)
			{
				if (highlighted != value)
				{
					highlighted = value;
					HighlightedChanged.Execute(GetNotifyEventArguments());
				}
			}

			collections::ObservableListBase<GuiRibbonGroup*>& GuiRibbonTabPage::GetGroups()
			{
				return groups;
			}

/***********************************************************************
GuiRibbonGroupItemCollection
***********************************************************************/

			bool GuiRibbonGroupItemCollection::QueryInsert(vint index, GuiControl* const& value)
			{
				return !value->GetBoundsComposition()->GetParent();
			}

			void GuiRibbonGroupItemCollection::AfterInsert(vint index, GuiControl* const& value)
			{
				value->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));

				auto item = new GuiStackItemComposition();
				item->AddChild(value->GetBoundsComposition());

				group->stack->InsertStackItem(index, item);
			}

			void GuiRibbonGroupItemCollection::AfterRemove(vint index, vint count)
			{
				for (vint i = 0; i < count; i++)
				{
					auto item = group->stack->GetStackItems()[index];
					group->stack->RemoveChild(item);

					item->RemoveChild(item->Children()[0]);
					delete item;
				}
			}

			GuiRibbonGroupItemCollection::GuiRibbonGroupItemCollection(GuiRibbonGroup* _group)
				:group(_group)
			{
			}

			GuiRibbonGroupItemCollection::~GuiRibbonGroupItemCollection()
			{
			}

/***********************************************************************
GuiRibbonGroup::CommandExecutor
***********************************************************************/

			GuiRibbonGroup::CommandExecutor::CommandExecutor(GuiRibbonGroup* _group)
				:group(_group)
			{
			}

			GuiRibbonGroup::CommandExecutor::~CommandExecutor()
			{
			}

			void GuiRibbonGroup::CommandExecutor::NotifyExpandButtonClicked()
			{
				group->ExpandButtonClicked.Execute(group->GetNotifyEventArguments());
			}

/***********************************************************************
GuiRibbonGroupMenu
***********************************************************************/

			class GuiRibbonGroupMenu : public GuiMenu, public Description<GuiRibbonGroupMenu>
			{
			private:
				IGuiMenuService::Direction GetPreferredDirection()override
				{
					return IGuiMenuService::Horizontal;
				}

				bool IsActiveState()override
				{
					return false;
				}

			public:
				GuiRibbonGroupMenu(theme::ThemeName themeName, GuiControl* _owner)
					:GuiMenu(themeName, _owner)
				{
				}
			};

/***********************************************************************
GuiRibbonGroup
***********************************************************************/

			void GuiRibbonGroup::BeforeControlTemplateUninstalled_()
			{
				auto ct = TypedControlTemplateObject(false);
				if (!ct) return;

				ct->SetCommands(nullptr);
			}

			void GuiRibbonGroup::AfterControlTemplateInstalled_(bool initialize)
			{
				{
					auto ct = TypedControlTemplateObject(true);
					ct->SetExpandable(expandable);
					ct->SetCollapsed(responsiveView->GetCurrentView() == responsiveFixedButton);
					ct->SetCommands(commandExecutor.Obj());
					dropdownButton->SetControlTemplate(ct->GetLargeDropdownButtonTemplate());
					dropdownMenu->SetControlTemplate(ct->GetSubMenuTemplate());
				}

				if (auto ct = dynamic_cast<GuiRibbonGroupMenuTemplate*>(dropdownMenu->TypedControlTemplateObject(true)))
				{
					ct->SetExpandable(expandable);
					ct->SetCommands(commandExecutor.Obj());
				}
			}

			bool GuiRibbonGroup::IsAltAvailable()
			{
				return alt != L"";
			}

			compositions::IGuiAltActionHost* GuiRibbonGroup::GetActivatingAltHost()
			{
				if (IsAltAvailable())
				{
					return this;
				}
				else
				{
					return GuiControl::GetActivatingAltHost();
				}
			}

			void GuiRibbonGroup::OnCachedBoundsChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				dropdownMenu->GetBoundsComposition()->SetPreferredMinSize(Size(0, containerComposition->GetCachedBounds().Height()));
			}

			void GuiRibbonGroup::OnTextChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				dropdownButton->SetText(GetText());
			}

			void GuiRibbonGroup::OnBeforeSubMenuOpening(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (responsiveView->GetViews().Contains(responsiveFixedButton))
				{
					auto currentDropdown = dropdownMenu;
					if (items.Count() == 1)
					{
						if (auto provider = items[0]->QueryTypedService<IGuiMenuDropdownProvider>())
						{
							if (auto menu = provider->ProvideDropdownMenu())
							{
								currentDropdown = menu;
							}
						}
					}
					dropdownButton->SetSubMenu(currentDropdown, false);
				}
			}

			void GuiRibbonGroup::OnBeforeSwitchingView(compositions::GuiGraphicsComposition* sender, compositions::GuiItemEventArgs& arguments)
			{
				if (auto ct = TypedControlTemplateObject(false))
				{
					ct->SetCollapsed(arguments.itemIndex == 1);
				}

				if (arguments.itemIndex == 0)
				{
					while (responsiveStack->LevelDown());
					dropdownMenu->GetContainerComposition()->RemoveChild(stack);
					responsiveStack->AddChild(stack);
					dropdownButton->SetSubMenu(nullptr, false);
				}
				else
				{
					while (responsiveStack->LevelUp());
					responsiveStack->RemoveChild(stack);
					dropdownMenu->GetContainerComposition()->AddChild(stack);
				}
			}

			GuiRibbonGroup::GuiRibbonGroup(theme::ThemeName themeName)
				:GuiControl(themeName)
				, items(this)
			{
				SetAltComposition(boundsComposition);
				SetAltControl(this, false);

				commandExecutor = Ptr(new CommandExecutor(this));
				{
					stack = new GuiStackComposition();
					stack->SetDirection(GuiStackComposition::Horizontal);
					stack->SetAlignmentToParent(Margin(0, 0, 0, 0));
					stack->SetPadding(2);
					stack->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

					responsiveStack = new GuiResponsiveStackComposition();
					responsiveStack->SetDirection(ResponsiveDirection::Horizontal);
					responsiveStack->SetAlignmentToParent(Margin(0, 0, 0, 0));
					responsiveStack->AddChild(stack);
				}
				{
					dropdownButton = new GuiToolstripButton(theme::ThemeName::RibbonLargeDropdownButton);
					dropdownButton->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));

					responsiveFixedButton = new GuiResponsiveFixedComposition();
					responsiveFixedButton->SetAlignmentToParent(Margin(0, 0, 0, 0));
					responsiveFixedButton->AddChild(dropdownButton->GetBoundsComposition());

					dropdownMenu = new GuiRibbonGroupMenu(theme::ThemeName::RibbonGroupMenu, dropdownButton);
				}

				responsiveView = new GuiResponsiveViewComposition();
				responsiveView->SetAlignmentToParent(Margin(0, 0, 0, 0));
				responsiveView->GetViews().Add(responsiveStack);

				containerComposition->AddChild(responsiveView);

				ExpandableChanged.SetAssociatedComposition(boundsComposition);
				ExpandButtonClicked.SetAssociatedComposition(boundsComposition);
				LargeImageChanged.SetAssociatedComposition(boundsComposition);

				TextChanged.AttachMethod(this, &GuiRibbonGroup::OnTextChanged);
				boundsComposition->CachedBoundsChanged.AttachMethod(this, &GuiRibbonGroup::OnCachedBoundsChanged);
				responsiveView->BeforeSwitchingView.AttachMethod(this, &GuiRibbonGroup::OnBeforeSwitchingView);
				dropdownButton->BeforeSubMenuOpening.AttachMethod(this, &GuiRibbonGroup::OnBeforeSubMenuOpening);
			}

			GuiRibbonGroup::~GuiRibbonGroup()
			{
				if (!responsiveView->GetViews().Contains(responsiveFixedButton))
				{
					SafeDeleteComposition(responsiveFixedButton);
				}
				delete dropdownMenu;
			}

			bool GuiRibbonGroup::GetExpandable()
			{
				return expandable;
			}

			void GuiRibbonGroup::SetExpandable(bool value)
			{
				if (expandable != value)
				{
					expandable = value;
					TypedControlTemplateObject(true)->SetExpandable(expandable);
					if (auto ct = dynamic_cast<GuiRibbonGroupMenuTemplate*>(dropdownMenu->TypedControlTemplateObject(true)))
					{
						ct->SetExpandable(expandable);
					}
					ExpandableChanged.Execute(GetNotifyEventArguments());
				}
			}

			Ptr<GuiImageData> GuiRibbonGroup::GetLargeImage()
			{
				return largeImage;
			}

			void GuiRibbonGroup::SetLargeImage(Ptr<GuiImageData> value)
			{
				if (largeImage != value)
				{
					largeImage = value;
					dropdownButton->SetLargeImage(value);
					LargeImageChanged.Execute(GetNotifyEventArguments());

					if (value)
					{
						if (!responsiveView->GetViews().Contains(responsiveFixedButton))
						{
							responsiveView->GetViews().Add(responsiveFixedButton);
						}
					}
					else
					{
						if (responsiveView->GetViews().Contains(responsiveFixedButton))
						{
							responsiveView->GetViews().Remove(responsiveFixedButton);
						}
					}
				}
			}

			collections::ObservableListBase<GuiControl*>& GuiRibbonGroup::GetItems()
			{
				return items;
			}

/***********************************************************************
GuiRibbonIconLabel
***********************************************************************/

			void GuiRibbonIconLabel::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiRibbonIconLabel::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				ct->SetImage(image);
			}

			GuiRibbonIconLabel::GuiRibbonIconLabel(theme::ThemeName themeName)
				:GuiControl(themeName)
			{
				ImageChanged.SetAssociatedComposition(boundsComposition);
			}

			GuiRibbonIconLabel::~GuiRibbonIconLabel()
			{
			}

			Ptr<GuiImageData> GuiRibbonIconLabel::GetImage()
			{
				return image;
			}

			void GuiRibbonIconLabel::SetImage(Ptr<GuiImageData> value)
			{
				if (image != value)
				{
					image = value;
					TypedControlTemplateObject(true)->SetImage(image);
					ImageChanged.Execute(GetNotifyEventArguments());
				}
			}

/***********************************************************************
GuiRibbonButtonsItemCollection
***********************************************************************/

			bool GuiRibbonButtonsItemCollection::QueryInsert(vint index, GuiControl* const& value)
			{
				return !value->GetBoundsComposition()->GetParent();
			}

			void GuiRibbonButtonsItemCollection::AfterInsert(vint index, GuiControl* const& value)
			{
				buttons->responsiveView->GetSharedControls().Add(value);
				buttons->SetButtonThemeName(buttons->responsiveView->GetCurrentView(), value);

				for (vint i = 0; i < sizeof(buttons->views) / sizeof(*buttons->views); i++)
				{
					if (auto view = buttons->views[i])
					{
						auto stack = dynamic_cast<GuiStackComposition*>(view->Children()[0]);

						auto shared = new GuiResponsiveSharedComposition();
						shared->SetAlignmentToParent(Margin(0, 0, 0, 0));
						shared->SetShared(value);

						auto item = new GuiStackItemComposition();
						item->AddChild(shared);

						stack->InsertStackItem(index, item);
					}
				}
			}

			void GuiRibbonButtonsItemCollection::BeforeRemove(vint index, GuiControl* const& value)
			{
				CHECK_FAIL(L"GuiRibbonButtonsItemCollection::BeforeRemove(vint, GuiControl* const&)#Controls are not allowed to be removed from GuiRibbonButtons.");
			}

			GuiRibbonButtonsItemCollection::GuiRibbonButtonsItemCollection(GuiRibbonButtons* _buttons)
				:buttons(_buttons)
			{
			}

			GuiRibbonButtonsItemCollection::~GuiRibbonButtonsItemCollection()
			{
			}

/***********************************************************************
GuiRibbonButtons
***********************************************************************/

			void GuiRibbonButtons::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiRibbonButtons::AfterControlTemplateInstalled_(bool initialize)
			{
				for (auto button : buttons)
				{
					SetButtonThemeName(responsiveView->GetCurrentView(), button);
				}
			}

			void GuiRibbonButtons::OnBeforeSwitchingView(compositions::GuiGraphicsComposition* sender, compositions::GuiItemEventArgs& arguments)
			{
				for (auto button : buttons)
				{
					SetButtonThemeName(responsiveView->GetViews()[arguments.itemIndex], button);
				}
			}

			void GuiRibbonButtons::SetButtonThemeName(compositions::GuiResponsiveCompositionBase* fixed, GuiControl* button)
			{
				if (fixed && button)
				{
					auto themeName = button->GetControlThemeName();
					vint type = -1;
					switch (themeName)
					{
					case ThemeName::RibbonLargeButton:
					case ThemeName::RibbonSmallButton:
					case ThemeName::ToolstripButton:
						type = 0;
						break;
					case ThemeName::RibbonLargeDropdownButton:
					case ThemeName::RibbonSmallDropdownButton:
					case ThemeName::ToolstripDropdownButton:
						type = 1;
						break;
					case ThemeName::RibbonLargeSplitButton:
					case ThemeName::RibbonSmallSplitButton:
					case ThemeName::ToolstripSplitButton:
						type = 2;
						break;
					case ThemeName::RibbonSmallIconLabel:
					case ThemeName::RibbonIconLabel:
						type = 3;
						break;
					default:;
					}

					if (type != -1)
					{
						ThemeName themeName = ThemeName::Unknown;
						TemplateProperty<GuiToolstripButtonTemplate> controlTemplate;

						if (fixed == views[(vint)RibbonButtonSize::Large])
						{
							switch (type)
							{
							case 0: themeName = ThemeName::RibbonLargeButton; break;
							case 1: themeName = ThemeName::RibbonLargeDropdownButton; break;
							case 2: themeName = ThemeName::RibbonLargeSplitButton; break;
							case 3: themeName = ThemeName::RibbonSmallIconLabel; break;
							}
						}
						else if (fixed == views[(vint)RibbonButtonSize::Small])
						{
							switch (type)
							{
							case 0: themeName = ThemeName::RibbonSmallButton; break;
							case 1: themeName = ThemeName::RibbonSmallDropdownButton; break;
							case 2: themeName = ThemeName::RibbonSmallSplitButton; break;
							case 3: themeName = ThemeName::RibbonSmallIconLabel; break;
							}
						}
						else if (fixed == views[(vint)RibbonButtonSize::Icon])
						{
							switch (type)
							{
							case 0: themeName = ThemeName::ToolstripButton; break;
							case 1: themeName = ThemeName::ToolstripDropdownButton; break;
							case 2: themeName = ThemeName::ToolstripSplitButton; break;
							case 3: themeName = ThemeName::RibbonIconLabel; break;
							}
						}

						if (auto ct = TypedControlTemplateObject(false))
						{
							if (fixed == views[(vint)RibbonButtonSize::Large])
							{
								switch (type)
								{
								case 0: controlTemplate = ct->GetLargeButtonTemplate(); break;
								case 1: controlTemplate = ct->GetLargeDropdownButtonTemplate(); break;
								case 2: controlTemplate = ct->GetLargeSplitButtonTemplate(); break;
								case 3: controlTemplate = ct->GetSmallIconLabelTemplate(); break;
								}
							}
							else if (fixed == views[(vint)RibbonButtonSize::Small])
							{
								switch (type)
								{
								case 0: controlTemplate = ct->GetSmallButtonTemplate(); break;
								case 1: controlTemplate = ct->GetSmallDropdownButtonTemplate(); break;
								case 2: controlTemplate = ct->GetSmallSplitButtonTemplate(); break;
								case 3: controlTemplate = ct->GetSmallIconLabelTemplate(); break;
								}
							}
							else if (fixed == views[(vint)RibbonButtonSize::Icon])
							{
								switch (type)
								{
								case 0: controlTemplate = ct->GetIconButtonTemplate(); break;
								case 1: controlTemplate = ct->GetIconDropdownButtonTemplate(); break;
								case 2: controlTemplate = ct->GetIconSplitButtonTemplate(); break;
								case 3: controlTemplate = ct->GetIconLabelTemplate(); break;
								}
							}
						}

						button->SetControlThemeNameAndTemplate(themeName, controlTemplate);
					}
				}
			}

			GuiRibbonButtons::GuiRibbonButtons(theme::ThemeName themeName, RibbonButtonSize _maxSize, RibbonButtonSize _minSize)
				:GuiControl(themeName)
				, maxSize(_maxSize)
				, minSize(_minSize)
				, buttons(this)
			{
				responsiveView = new GuiResponsiveViewComposition();
				responsiveView->SetDirection(ResponsiveDirection::Horizontal);
				responsiveView->SetAlignmentToParent(Margin(0, 0, 0, 0));
				responsiveView->BeforeSwitchingView.AttachMethod(this, &GuiRibbonButtons::OnBeforeSwitchingView);

				auto installButton = [&](GuiTableComposition* table, vint row, vint column, GuiControl* buttonContainer)
				{
					auto shared = new GuiResponsiveSharedComposition();
					shared->SetAlignmentToParent(Margin(0, 0, 0, 0));
					shared->SetShared(buttonContainer);

					auto cell = new GuiCellComposition();
					cell->SetSite(row, column, 1, 1);
					cell->AddChild(shared);

					table->AddChild(cell);
				};

				for (vint i = 0; i < sizeof(views) / sizeof(*views); i++)
				{
					if ((vint)maxSize <= i && i <= (vint)minSize)
					{
						auto stack = new GuiStackComposition();
						stack->SetAlignmentToParent(Margin(0, 0, 0, 0));
						stack->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
						stack->SetDirection(i == 0 ? GuiStackComposition::Horizontal : GuiStackComposition::Vertical);

						views[i] = new GuiResponsiveFixedComposition();
						views[i]->AddChild(stack);
						responsiveView->GetViews().Add(views[i]);
					}
				}

				auto sharedSizeRootComposition = new GuiSharedSizeRootComposition();
				sharedSizeRootComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				sharedSizeRootComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				sharedSizeRootComposition->AddChild(responsiveView);

				containerComposition->AddChild(sharedSizeRootComposition);
			}

			GuiRibbonButtons::~GuiRibbonButtons()
			{
			}

			collections::ObservableListBase<GuiControl*>& GuiRibbonButtons::GetButtons()
			{
				return buttons;
			}

/***********************************************************************
GuiRibbonToolstripsGroupCollection
***********************************************************************/

			bool GuiRibbonToolstripsGroupCollection::QueryInsert(vint index, GuiToolstripGroup* const& value)
			{
				return !value->GetBoundsComposition()->GetParent();
			}

			void GuiRibbonToolstripsGroupCollection::AfterInsert(vint index, GuiToolstripGroup* const& value)
			{
				toolstrips->RearrangeToolstripGroups();
			}

			void GuiRibbonToolstripsGroupCollection::AfterRemove(vint index, vint count)
			{
				toolstrips->RearrangeToolstripGroups();
			}

			GuiRibbonToolstripsGroupCollection::GuiRibbonToolstripsGroupCollection(GuiRibbonToolstrips* _toolstrips)
				:toolstrips(_toolstrips)
			{
			}

			GuiRibbonToolstripsGroupCollection::~GuiRibbonToolstripsGroupCollection()
			{
			}

/***********************************************************************
GuiRibbonToolstrips
***********************************************************************/

// TODO: (enumerable) foreach
#define ARRLEN(X) sizeof(X) / sizeof(*X)

			void GuiRibbonToolstrips::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiRibbonToolstrips::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				for (vint i = 0; i < ARRLEN(toolbars); i++)
				{
					toolbars[i]->SetControlTemplate(ct->GetToolbarTemplate());
				}
			}

			void GuiRibbonToolstrips::OnBeforeSwitchingView(compositions::GuiGraphicsComposition* sender, compositions::GuiItemEventArgs& arguments)
			{
				RearrangeToolstripGroups(arguments.itemIndex);
			}

			void GuiRibbonToolstrips::RearrangeToolstripGroups(vint viewIndex)
			{
				static_assert(ARRLEN(longContainers) == 2, "");
				static_assert(ARRLEN(shortContainers) == 3, "");

				if (viewIndex == -1)
				{
					viewIndex = responsiveView->GetViews().IndexOf(responsiveView->GetCurrentView());
				}

				for (vint i = 0; i < ARRLEN(longContainers); i++)
				{
					longContainers[i]->GetToolstripItems().Clear();
				}
				for (vint i = 0; i < ARRLEN(shortContainers); i++)
				{
					shortContainers[i]->GetToolstripItems().Clear();
				}

				vint count = viewIndex == 0 ? 2 : 3;

				if (groups.Count() <= count)
				{
					auto containers = viewIndex == 0 ? longContainers : shortContainers;
					// TODO: (enumerable) foreach:indexed
					for (vint i = 0; i < groups.Count(); i++)
					{
						containers[i]->GetToolstripItems().Add(groups[i]);
					}
				}
				else if (count == 3)
				{
#define DELTA(POSTFIX) (abs(count1##POSTFIX - count2##POSTFIX) + abs(count2##POSTFIX - count3##POSTFIX) + abs(count3##POSTFIX - count1##POSTFIX))
#define DEFINE_COUNT(POSTFIX, OFFSET_FIRST, OFFSET_LAST) \
					vint count1##POSTFIX = count1_o + (OFFSET_FIRST); \
					vint count2##POSTFIX = count2_o - (OFFSET_FIRST) - (OFFSET_LAST); \
					vint count3##POSTFIX = count3_o + (OFFSET_LAST)
#define MIN(a, b) (a)<(b)?(a):(b)

					vint firstGroupCount = 0;
					vint lastGroupCount = 0;

					vint count1_o = 0;
					vint count2_o = From(groups)
						.Select([](GuiToolstripGroup* group) {return group->GetToolstripItems().Count(); })
						.Aggregate([](vint a, vint b) {return a + b; });
					vint count3_o = 0;
					vint delta_o = DELTA(_o);

					while (firstGroupCount + lastGroupCount < groups.Count())
					{
						auto newFirstGroup = groups[firstGroupCount];
						auto newLastGroup = groups[groups.Count() - lastGroupCount - 1];

						DEFINE_COUNT(_f, newFirstGroup->GetToolstripItems().Count(), 0);
						vint delta_f = DELTA(_f);

						DEFINE_COUNT(_l, 0, newLastGroup->GetToolstripItems().Count());
						vint delta_l = DELTA(_l);

						vint delta = MIN(delta_o, MIN(delta_f, delta_l));
						if (delta == delta_f)
						{
							firstGroupCount++;
							count1_o = count1_f;
							count2_o = count2_f;
							count3_o = count3_f;
							delta_o = delta_f;
						}
						else if (delta == delta_l)
						{
							lastGroupCount++;
							count1_o = count1_l;
							count2_o = count2_l;
							count3_o = count3_l;
							delta_o = delta_l;
						}
						else
						{
							break;
						}
					}

					vint minMiddle = firstGroupCount;
					vint maxMiddle = groups.Count() - lastGroupCount - 1;
					// TODO: (enumerable) foreach:indexed
					for (vint j = 0; j < groups.Count(); j++)
					{
						shortContainers[
							j < minMiddle ? 0 :
							j>maxMiddle ? 2 :
							1
						]->GetToolstripItems().Add(groups[j]);
					}

#undef MIN
#undef DEFINE_COUNT
#undef DELTA
				}
				else if (count == 2)
				{
					vint firstGroupCount = groups.Count();
					{
						vint count1 = 0;
						vint count2 = From(groups)
							.Select([](GuiToolstripGroup* group) {return group->GetToolstripItems().Count(); })
							.Aggregate([](vint a, vint b) {return a + b; });
						vint delta = abs(count2 - count1);

						// TODO: (enumerable) foreach
						for (vint i = 0; i < groups.Count(); i++)
						{
							auto groupCount = groups[i]->GetToolstripItems().Count();
							vint count1_2 = count1 + groupCount;
							vint count2_2 = count2 - groupCount;
							vint delta_2 = abs(count2_2 - count1_2);

							if (delta < delta_2)
							{
								firstGroupCount = i;
								break;
							}

							count1 = count1_2;
							count2 = count2_2;
							delta = delta_2;
						}
					}

					// TODO: (enumerable) foreach:indexed
					for (vint j = 0; j < groups.Count(); j++)
					{
						longContainers[j < firstGroupCount ? 0 : 1]->GetToolstripItems().Add(groups[j]);
					}
				}
			}

			GuiRibbonToolstrips::GuiRibbonToolstrips(theme::ThemeName themeName)
				:GuiControl(themeName)
				, groups(this)
			{
				responsiveView = new GuiResponsiveViewComposition();
				responsiveView->SetDirection(ResponsiveDirection::Horizontal);
				responsiveView->SetAlignmentToParent(Margin(0, 0, 0, 0));
				responsiveView->BeforeSwitchingView.AttachMethod(this, &GuiRibbonToolstrips::OnBeforeSwitchingView);

				vint toolbarIndex = 0;
				// TODO: (enumerable) foreach:indexed
				for (vint i = 0; i < sizeof(views) / sizeof(*views); i++)
				{
					auto containers = i == 0 ? longContainers : shortContainers;
					vint count = i == 0 ? 2 : 3;

					auto table = new GuiTableComposition();
					table->SetAlignmentToParent(Margin(0, 0, 0, 0));
					table->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					
					table->SetRowsAndColumns(count * 2 + 1, 1);
					table->SetColumnOption(0, GuiCellOption::MinSizeOption());
					table->SetRowOption(0, GuiCellOption::PercentageOption(1.0));
					for (vint j = 0; j < count; j++)
					{
						table->SetRowOption(j * 2 + 1, GuiCellOption::MinSizeOption());
						table->SetRowOption(j * 2 + 2, GuiCellOption::PercentageOption(1.0));
					}

					for (vint j = 0; j < count; j++)
					{
						auto toolbar = new GuiToolstripToolBar(theme::ThemeName::ToolstripToolBar);
						toolbar->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
						toolbars[toolbarIndex++] = toolbar;

						auto cell = new GuiCellComposition();
						cell->SetSite(j * 2 + 1, 0, 1, 1);
						cell->AddChild(toolbar->GetBoundsComposition());
						table->AddChild(cell);

						auto container = new GuiToolstripGroupContainer(theme::ThemeName::CustomControl);
						toolbar->GetToolstripItems().Add(container);
						containers[j] = container;
					}

					views[i] = new GuiResponsiveFixedComposition();
					views[i]->AddChild(table);
					responsiveView->GetViews().Add(views[i]);
				}

				containerComposition->AddChild(responsiveView);
			}

			GuiRibbonToolstrips::~GuiRibbonToolstrips()
			{
			}

			collections::ObservableListBase<GuiToolstripGroup*>& GuiRibbonToolstrips::GetGroups()
			{
				return groups;
			}

#undef ARRLEN

/***********************************************************************
GuiRibbonGallery::CommandExecutor
***********************************************************************/

			GuiRibbonGallery::CommandExecutor::CommandExecutor(GuiRibbonGallery* _gallery)
				:gallery(_gallery)
			{
			}

			GuiRibbonGallery::CommandExecutor::~CommandExecutor()
			{
			}

			void GuiRibbonGallery::CommandExecutor::NotifyScrollUp()
			{
				gallery->RequestedScrollUp.Execute(gallery->GetNotifyEventArguments());
			}

			void GuiRibbonGallery::CommandExecutor::NotifyScrollDown()
			{
				gallery->RequestedScrollDown.Execute(gallery->GetNotifyEventArguments());
			}

			void GuiRibbonGallery::CommandExecutor::NotifyDropdown()
			{
				gallery->RequestedDropdown.Execute(gallery->GetNotifyEventArguments());
			}

/***********************************************************************
GuiRibbonGallery
***********************************************************************/

			void GuiRibbonGallery::BeforeControlTemplateUninstalled_()
			{
				auto ct = TypedControlTemplateObject(false);
				if (!ct) return;

				ct->SetCommands(nullptr);
			}

			void GuiRibbonGallery::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				ct->SetCommands(commandExecutor.Obj());
				ct->SetScrollUpEnabled(scrollUpEnabled);
				ct->SetScrollDownEnabled(scrollDownEnabled);
			}

			GuiRibbonGallery::GuiRibbonGallery(theme::ThemeName themeName)
				:GuiControl(themeName)
			{
				commandExecutor = Ptr(new CommandExecutor(this));

				ScrollUpEnabledChanged.SetAssociatedComposition(boundsComposition);
				ScrollDownEnabledChanged.SetAssociatedComposition(boundsComposition);
				RequestedScrollUp.SetAssociatedComposition(boundsComposition);
				RequestedScrollDown.SetAssociatedComposition(boundsComposition);
				RequestedDropdown.SetAssociatedComposition(boundsComposition);
			}

			GuiRibbonGallery::~GuiRibbonGallery()
			{
			}

			bool GuiRibbonGallery::GetScrollUpEnabled()
			{
				return scrollUpEnabled;
			}

			void GuiRibbonGallery::SetScrollUpEnabled(bool value)
			{
				if (scrollUpEnabled != value)
				{
					scrollUpEnabled = value;
					TypedControlTemplateObject(true)->SetScrollUpEnabled(value);
				}
			}

			bool GuiRibbonGallery::GetScrollDownEnabled()
			{
				return scrollDownEnabled;
			}

			void GuiRibbonGallery::SetScrollDownEnabled(bool value)
			{
				if (scrollDownEnabled != value)
				{
					scrollDownEnabled = value;
					TypedControlTemplateObject(true)->SetScrollDownEnabled(value);
				}
			}

/***********************************************************************
GuiRibbonToolstripMenu
***********************************************************************/

			void GuiRibbonToolstripMenu::BeforeControlTemplateUninstalled_()
			{
				auto ct = TypedControlTemplateObject(false);
				if (!ct) return;

				if (auto cc = ct->GetContentComposition())
				{
					cc->RemoveChild(contentComposition);
				}
			}

			void GuiRibbonToolstripMenu::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				if (auto cc = ct->GetContentComposition())
				{
					cc->AddChild(contentComposition);
				}
			}

			GuiRibbonToolstripMenu::GuiRibbonToolstripMenu(theme::ThemeName themeName, GuiControl* owner)
				:GuiToolstripMenu(themeName, owner)
			{
				contentComposition = new GuiBoundsComposition();
				contentComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				contentComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
			}

			GuiRibbonToolstripMenu::~GuiRibbonToolstripMenu()
			{
				if (!contentComposition->GetParent())
				{
					SafeDeleteComposition(contentComposition);
				}
			}

			compositions::GuiGraphicsComposition* GuiRibbonToolstripMenu::GetContentComposition()
			{
				return contentComposition;
			}
		}
	}
}


/***********************************************************************
.\CONTROLS\TOOLSTRIPPACKAGE\GUIRIBBONGALLERYLIST.CPP
***********************************************************************/


namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace reflection::description;
			using namespace collections;
			using namespace compositions;
			using namespace templates;

			namespace list
			{

/***********************************************************************
list::GalleryGroup
***********************************************************************/

				GalleryGroup::GalleryGroup()
				{
				}

				GalleryGroup::~GalleryGroup()
				{
					if (eventHandler)
					{
						itemValues.Cast<IValueObservableList>()->ItemChanged.Remove(eventHandler);
					}
				}

				WString GalleryGroup::GetName()
				{
					return name;
				}

				Ptr<IValueList> GalleryGroup::GetItemValues()
				{
					return itemValues;
				}

/***********************************************************************
list::GroupedDataSource
***********************************************************************/

				void GroupedDataSource::RebuildItemSource()
				{
					ignoreGroupChanged = true;
					joinedItemSource.Clear();
					groupedItemSource.Clear();
					cachedGroupItemCounts.Clear();
					ignoreGroupChanged = false;

					if (itemSource)
					{
						if (GetGroupEnabled())
						{
							for (auto [groupValue, index] : indexed(GetLazyList<Value>(itemSource)))
							{
								auto group = Ptr(new GalleryGroup);
								group->name = titleProperty(groupValue);
								group->itemValues = GetChildren(childrenProperty(groupValue));
								AttachGroupChanged(group, index);
								groupedItemSource.Add(group);
							}
						}
						else
						{
							auto group = Ptr(new GalleryGroup);
							group->itemValues = GetChildren(itemSource);
							AttachGroupChanged(group, 0);
							groupedItemSource.Add(group);
						}
					}
				}

				Ptr<IValueList> GroupedDataSource::GetChildren(Ptr<IValueEnumerable> children)
				{
					if (!children)
					{
						return nullptr;
					}
					else if (auto list = children.Cast<IValueList>())
					{
						return list;
					}
					else
					{
						return IValueList::Create(GetLazyList<Value>(children));
					}
				}

				void GroupedDataSource::AttachGroupChanged(Ptr<GalleryGroup> group, vint index)
				{
					if (auto observable = group->itemValues.Cast<IValueObservableList>())
					{
						group->eventHandler = observable->ItemChanged.Add([this, index](vint start, vint oldCount, vint newCount)
						{
							OnGroupItemChanged(index, start, oldCount, newCount);
						});
					}
				}

				void GroupedDataSource::OnGroupChanged(vint start, vint oldCount, vint newCount)
				{
					if (!ignoreGroupChanged)
					{
						for (vint i = 0; i < oldCount; i++)
						{
							RemoveGroupFromJoined(start);
						}
						for (vint i = 0; i < newCount; i++)
						{
							InsertGroupToJoined(start + i);
						}
					}
				}

				void GroupedDataSource::OnGroupItemChanged(vint index, vint start, vint oldCount, vint newCount)
				{
					if (!ignoreGroupChanged)
					{
						vint countBeforeGroup = GetCountBeforeGroup(index);
						vint joinedIndex = countBeforeGroup + start;
						vint minCount = oldCount < newCount ? oldCount : newCount;
						auto itemValues = groupedItemSource[index]->itemValues;

						for (vint i = 0; i < minCount; i++)
						{
							joinedItemSource.Set(joinedIndex + i, itemValues->Get(start + i));
						}

						if (oldCount < newCount)
						{
							for (vint i = minCount; i < newCount; i++)
							{
								joinedItemSource.Insert(joinedIndex + i, itemValues->Get(start + i));
							}
						}
						else if (oldCount > newCount)
						{
							for (vint i = minCount; i < oldCount; i++)
							{
								joinedItemSource.RemoveAt(joinedIndex + i);
							}
						}

						cachedGroupItemCounts[index] += newCount - oldCount;
					}
				}

				vint GroupedDataSource::GetCountBeforeGroup(vint index)
				{
					vint count = 0;
					for (vint i = 0; i < index; i++)
					{
						count += cachedGroupItemCounts[i];
					}
					return count;
				}

				void GroupedDataSource::InsertGroupToJoined(vint index)
				{
					vint countBeforeGroup = GetCountBeforeGroup(index);
					auto group = groupedItemSource[index];
					vint itemCount = group->itemValues ? group->itemValues->GetCount() : 0;
					cachedGroupItemCounts.Insert(index, itemCount);

					if (itemCount > 0)
					{
						for (vint i = 0; i < itemCount; i++)
						{
							joinedItemSource.Insert(countBeforeGroup + i, group->itemValues->Get(i));
						}
					}
				}

				void GroupedDataSource::RemoveGroupFromJoined(vint index)
				{
					vint countBeforeGroup = GetCountBeforeGroup(index);
					joinedItemSource.RemoveRange(countBeforeGroup, cachedGroupItemCounts[index]);
					cachedGroupItemCounts.RemoveAt(index);
				}

				GroupedDataSource::GroupedDataSource(compositions::GuiGraphicsComposition* _associatedComposition)
					:associatedComposition(_associatedComposition)
				{
					GroupEnabledChanged.SetAssociatedComposition(associatedComposition);
					GroupTitlePropertyChanged.SetAssociatedComposition(associatedComposition);
					GroupChildrenPropertyChanged.SetAssociatedComposition(associatedComposition);

					auto vol = UnboxValue<Ptr<IValueObservableList>>(BoxParameter(groupedItemSource));
					groupChangedHandler = vol->ItemChanged.Add(this, &GroupedDataSource::OnGroupChanged);
				}

				GroupedDataSource::~GroupedDataSource()
				{
					auto vol = UnboxValue<Ptr<IValueObservableList>>(BoxParameter(joinedItemSource));
					vol->ItemChanged.Remove(groupChangedHandler);
				}

				Ptr<IValueEnumerable> GroupedDataSource::GetItemSource()
				{
					return itemSource;
				}

				void GroupedDataSource::SetItemSource(Ptr<IValueEnumerable> value)
				{
					if (itemSource != value)
					{
						itemSource = value;
						RebuildItemSource();
					}
				}

				bool GroupedDataSource::GetGroupEnabled()
				{
					return titleProperty && childrenProperty;
				}

				ItemProperty<WString> GroupedDataSource::GetGroupTitleProperty()
				{
					return titleProperty;
				}

				void GroupedDataSource::SetGroupTitleProperty(const ItemProperty<WString>& value)
				{
					if (titleProperty != value)
					{
						titleProperty = value;
						GroupTitlePropertyChanged.Execute(GuiEventArgs(associatedComposition));
						GroupEnabledChanged.Execute(GuiEventArgs(associatedComposition));
						RebuildItemSource();
					}
				}

				ItemProperty<Ptr<IValueEnumerable>> GroupedDataSource::GetGroupChildrenProperty()
				{
					return childrenProperty;
				}

				void GroupedDataSource::SetGroupChildrenProperty(const ItemProperty<Ptr<IValueEnumerable>>& value)
				{
					if (childrenProperty != value)
					{
						childrenProperty = value;
						GroupChildrenPropertyChanged.Execute(GuiEventArgs(associatedComposition));
						GroupEnabledChanged.Execute(GuiEventArgs(associatedComposition));
						RebuildItemSource();
					}
				}

				const GroupedDataSource::GalleryGroupList& GroupedDataSource::GetGroups()
				{
					return groupedItemSource;
				}
			}

/***********************************************************************
GuiBindableRibbonGalleryList
***********************************************************************/

			void GuiBindableRibbonGalleryList::BeforeControlTemplateUninstalled_()
			{
			}

			void GuiBindableRibbonGalleryList::AfterControlTemplateInstalled_(bool initialize)
			{
				auto ct = TypedControlTemplateObject(true);
				itemList->SetControlTemplate(ct->GetItemListTemplate());
				subMenu->SetControlTemplate(ct->GetMenuTemplate());
				groupContainer->SetControlTemplate(ct->GetGroupContainerTemplate());
				MenuResetGroupTemplate();
				UpdateLayoutSizeOffset();
			}

			void GuiBindableRibbonGalleryList::UpdateLayoutSizeOffset()
			{
				auto cSize = itemList->GetContainerComposition()->GetCachedBounds();
				auto bSize = itemList->GetBoundsComposition()->GetCachedBounds();
				layout->SetSizeOffset(Size(bSize.Width() - cSize.Width(), bSize.Height() - cSize.Height()));

				if (layout->GetItemWidth() > 0)
				{
					vint columns = layout->GetVisibleItemCount();
					if (columns == 0) columns = 1;
					vint rows = (visibleItemCount + columns - 1) / columns;
					vint height = (vint)(layout->GetCachedBounds().Height()*(rows + 0.5));
					groupContainer->GetBoundsComposition()->SetPreferredMinSize(Size(0, height));
				}
				else
				{
					groupContainer->GetBoundsComposition()->SetPreferredMinSize(Size(0, 0));
				}
			}

			void GuiBindableRibbonGalleryList::OnItemListSelectionChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				auto pos = IndexToGalleryPos(itemList->GetSelectedItemIndex());
				// TODO: (enumerable) foreach
				for (vint i = 0; i < groupedItemSource.Count(); i++)
				{
					auto group = groupedItemSource[i];
					if (group->GetItemValues())
					{
						vint count = group->GetItemValues()->GetCount();
						for (vint j = 0; j < count; j++)
						{
							auto background = MenuGetGroupItemBackground(i, j);
							background->SetSelected(pos.group == i && pos.item == j);
						}
					}
				}
				
				if (!skipItemAppliedEvent && itemList->GetSelectedItemIndex() != -1)
				{
					GuiItemEventArgs itemAppliedArgs(boundsComposition);
					itemAppliedArgs.itemIndex = itemList->GetSelectedItemIndex();
					ItemApplied.Execute(itemAppliedArgs);
				}
				SelectionChanged.Execute(GetNotifyEventArguments());
			}

			void GuiBindableRibbonGalleryList::OnItemListItemMouseEnter(compositions::GuiGraphicsComposition* sender, compositions::GuiItemEventArgs& arguments)
			{
				StartPreview(arguments.itemIndex);
			}

			void GuiBindableRibbonGalleryList::OnItemListItemMouseLeave(compositions::GuiGraphicsComposition* sender, compositions::GuiItemEventArgs& arguments)
			{
				StopPreview(arguments.itemIndex);
			}

			void GuiBindableRibbonGalleryList::OnCachedBoundsChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				UpdateLayoutSizeOffset();

				auto bounds = boundsComposition->GetCachedBounds();
				subMenu->GetBoundsComposition()->SetPreferredMinSize(Size(bounds.Width() + 20, 1));

				// TODO: (enumerable) foreach
				for (vint i = 0; i < groupedItemSource.Count(); i++)
				{
					auto group = groupedItemSource[i];
					if (group->GetItemValues())
					{
						vint count = group->GetItemValues()->GetCount();
						for (vint j = 0; j < count; j++)
						{
							auto background = MenuGetGroupItemBackground(i, j);
							background->GetBoundsComposition()->SetPreferredMinSize(Size(0, bounds.Height()));
						}
					}
				}
			}

			void GuiBindableRibbonGalleryList::OnRequestedDropdown(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				subMenu->ShowPopup(this, Point(0, 0));
			}

			void GuiBindableRibbonGalleryList::OnRequestedScrollUp(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				itemListArranger->ScrollUp();
			}

			void GuiBindableRibbonGalleryList::OnRequestedScrollDown(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				itemListArranger->ScrollDown();
			}

			void GuiBindableRibbonGalleryList::MenuResetGroupTemplate()
			{
				groupStack->SetItemTemplate([this](const Value& groupValue)->GuiTemplate*
				{
					auto group = UnboxValue<Ptr<list::GalleryGroup>>(groupValue);

					auto groupTemplate = new GuiTemplate;
					groupTemplate->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

					auto groupContentStack = new GuiStackComposition;
					groupContentStack->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					groupContentStack->SetAlignmentToParent(Margin(0, 0, 0, 0));
					groupContentStack->SetDirection(GuiStackComposition::Vertical);
					{
						auto item = new GuiStackItemComposition;
						groupContentStack->AddChild(item);

						auto header = new GuiControl(theme::ThemeName::RibbonToolstripHeader);
						header->SetControlTemplate(TypedControlTemplateObject(true)->GetHeaderTemplate());
						header->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
						header->SetText(group->GetName());
						item->AddChild(header->GetBoundsComposition());
					}
					if (itemStyle)
					{
						auto item = new GuiStackItemComposition;
						item->SetPreferredMinSize(Size(1, 1));
						groupContentStack->AddChild(item);

						auto groupItemFlow = new GuiRepeatFlowComposition();
						groupItemFlow->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
						groupItemFlow->SetAlignmentToParent(Margin(0, 0, 0, 0));
						groupItemFlow->SetItemSource(group->GetItemValues());
						groupItemFlow->SetItemTemplate([=, this](const Value& groupItemValue)->GuiTemplate*
						{
							auto groupItemTemplate = new GuiTemplate;
							groupItemTemplate->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);

							auto backgroundButton = new GuiSelectableButton(theme::ThemeName::ListItemBackground);
							if (auto style = TypedControlTemplateObject(true)->GetBackgroundTemplate())
							{
								backgroundButton->SetControlTemplate(style);
							}
							backgroundButton->SetAutoFocus(false);
							backgroundButton->SetAutoSelection(false);
							backgroundButton->BeforeClicked.AttachLambda([=, this](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
							{
								auto groupIndex = groupStack->GetStackItems().IndexOf(dynamic_cast<GuiStackItemComposition*>(groupTemplate->GetParent()));
								auto itemIndex = groupItemFlow->GetFlowItems().IndexOf(dynamic_cast<GuiFlowItemComposition*>(groupItemTemplate->GetParent()));
								auto index = GalleryPosToIndex({ groupIndex,itemIndex });
								itemList->SetSelected(index, true);
								itemList->EnsureItemVisible(index);
								subMenu->Close();
							});
							backgroundButton->GetBoundsComposition()->GetEventReceiver()->mouseEnter.AttachLambda([=, this](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
							{
								auto groupIndex = groupStack->GetStackItems().IndexOf(dynamic_cast<GuiStackItemComposition*>(groupTemplate->GetParent()));
								auto itemIndex = groupItemFlow->GetFlowItems().IndexOf(dynamic_cast<GuiFlowItemComposition*>(groupItemTemplate->GetParent()));
								auto index = GalleryPosToIndex({ groupIndex,itemIndex });
								StartPreview(index);
							});
							backgroundButton->GetBoundsComposition()->GetEventReceiver()->mouseLeave.AttachLambda([=, this](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
							{
								auto groupIndex = groupStack->GetStackItems().IndexOf(dynamic_cast<GuiStackItemComposition*>(groupTemplate->GetParent()));
								auto itemIndex = groupItemFlow->GetFlowItems().IndexOf(dynamic_cast<GuiFlowItemComposition*>(groupItemTemplate->GetParent()));
								auto index = GalleryPosToIndex({ groupIndex,itemIndex });
								StopPreview(index);
							});
							groupItemTemplate->AddChild(backgroundButton->GetBoundsComposition());

							auto itemTemplate = itemStyle(groupItemValue);
							itemTemplate->SetAlignmentToParent(Margin(0, 0, 0, 0));
							backgroundButton->GetContainerComposition()->AddChild(itemTemplate);

							return groupItemTemplate;
						});
						item->AddChild(groupItemFlow);
					}
					groupTemplate->AddChild(groupContentStack);

					return groupTemplate;
				});
			}

			GuiControl* GuiBindableRibbonGalleryList::MenuGetGroupHeader(vint groupIndex)
			{
				CHECK_ERROR(0 <= groupIndex && groupIndex < groupedItemSource.Count(), L"GuiBindableRibbonGalleryList::MenuGetGroupHeader(vint)#Group index out of range");
				auto stackItem = groupStack->GetStackItems()[groupIndex];
				auto groupTemplate = stackItem->Children()[0];
				auto groupContentStack = dynamic_cast<GuiStackComposition*>(groupTemplate->Children()[0]);
				auto groupHeaderItem = groupContentStack->GetStackItems()[0];
				auto groupHeader = groupHeaderItem->Children()[0]->GetAssociatedControl();
				CHECK_ERROR(groupHeader, L"GuiBindableRibbonGalleryList::MenuGetGroupHeader(vint)#Internal error.");
				return groupHeader;
			}

			compositions::GuiRepeatFlowComposition* GuiBindableRibbonGalleryList::MenuGetGroupFlow(vint groupIndex)
			{
				CHECK_ERROR(0 <= groupIndex && groupIndex < groupedItemSource.Count(), L"GuiBindableRibbonGalleryList::MenuGetGroupFlow(vint)#Group index out of range");
				if (!itemStyle) return nullptr;
				auto stackItem = groupStack->GetStackItems()[groupIndex];
				auto groupTemplate = stackItem->Children()[0];
				auto groupContentStack = dynamic_cast<GuiStackComposition*>(groupTemplate->Children()[0]);
				auto groupContentItem = groupContentStack->GetStackItems()[1];
				auto groupFlow = dynamic_cast<GuiRepeatFlowComposition*>(groupContentItem->Children()[0]);
				CHECK_ERROR(groupFlow, L"GuiBindableRibbonGalleryList::MenuGetGroupHeader(vint)#Internal error.");
				return groupFlow;
			}

			GuiSelectableButton* GuiBindableRibbonGalleryList::MenuGetGroupItemBackground(vint groupIndex, vint itemIndex)
			{
				CHECK_ERROR(0 <= groupIndex && groupIndex < groupedItemSource.Count(), L"GuiBindableRibbonGalleryList::MenuGetGroupItemBackground(vint, vint)#Group index out of range");
				auto group = groupedItemSource[groupIndex];
				CHECK_ERROR(group->GetItemValues() && 0 <= itemIndex && itemIndex < group->GetItemValues()->GetCount(), L"GuiBindableRibbonGalleryList::MenuGetGroupHeader(vint, vint)#Item index out of range");

				auto groupFlow = MenuGetGroupFlow(groupIndex);
				auto groupFlowItem = groupFlow->GetFlowItems()[itemIndex];
				auto groupItemTemplate = groupFlowItem->Children()[0];
				auto groupItemBackground = dynamic_cast<GuiSelectableButton*>(groupItemTemplate->Children()[0]->GetAssociatedControl());
				CHECK_ERROR(groupItemBackground, L"GuiBindableRibbonGalleryList::MenuGetGroupHeader(vint, vint)#Internal error.");
				return groupItemBackground;
			}

			void GuiBindableRibbonGalleryList::StartPreview(vint index)
			{
				if (index != itemList->GetSelectedItemIndex())
				{
					GuiItemEventArgs previewArgs(boundsComposition);
					previewArgs.itemIndex = index;
					PreviewStarted.Execute(previewArgs);
				}
			}

			void GuiBindableRibbonGalleryList::StopPreview(vint index)
			{
				if (index != itemList->GetSelectedItemIndex())
				{
					GuiItemEventArgs previewArgs(boundsComposition);
					previewArgs.itemIndex = index;
					PreviewStopped.Execute(previewArgs);
				}
			}

			GuiMenu* GuiBindableRibbonGalleryList::ProvideDropdownMenu()
			{
				return GetSubMenu();
			}

			GuiBindableRibbonGalleryList::GuiBindableRibbonGalleryList(theme::ThemeName themeName)
				:GuiRibbonGallery(themeName)
				, GroupedDataSource(boundsComposition)
			{
				ItemTemplateChanged.SetAssociatedComposition(boundsComposition);
				SelectionChanged.SetAssociatedComposition(boundsComposition);
				PreviewStarted.SetAssociatedComposition(boundsComposition);
				PreviewStopped.SetAssociatedComposition(boundsComposition);
				ItemApplied.SetAssociatedComposition(boundsComposition);
				subMenu = new GuiRibbonToolstripMenu(theme::ThemeName::RibbonToolstripMenu, this);

				{
					layout = new ribbon_impl::GalleryResponsiveLayout;
					layout->SetAlignmentToParent(Margin(0, 0, 0, 0));
					containerComposition->AddChild(layout);

					itemListArranger = new ribbon_impl::GalleryItemArranger(this);
					itemList = new GuiBindableTextList(theme::ThemeName::RibbonGalleryItemList);
					itemList->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
					itemList->SetArranger(Ptr(itemListArranger));
					itemList->SetItemSource(UnboxValue<Ptr<IValueObservableList>>(BoxParameter(joinedItemSource)));
					itemList->SelectionChanged.AttachMethod(this, &GuiBindableRibbonGalleryList::OnItemListSelectionChanged);
					itemList->ItemMouseEnter.AttachMethod(this, &GuiBindableRibbonGalleryList::OnItemListItemMouseEnter);
					itemList->ItemMouseLeave.AttachMethod(this, &GuiBindableRibbonGalleryList::OnItemListItemMouseLeave);
					layout->AddChild(itemList->GetBoundsComposition());
				}
				{
					groupContainer = new GuiScrollContainer(theme::ThemeName::ScrollView);
					groupContainer->SetHorizontalAlwaysVisible(false);
					groupContainer->SetVerticalAlwaysVisible(false);
					groupContainer->SetExtendToFullWidth(true);
					groupContainer->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
					subMenu->GetContentComposition()->AddChild(groupContainer->GetBoundsComposition());

					groupStack = new GuiRepeatStackComposition();
					groupStack->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					groupStack->SetAlignmentToParent(Margin(0, 0, 0, 0));
					groupStack->SetDirection(GuiStackComposition::Vertical);
					groupStack->SetItemSource(UnboxValue<Ptr<IValueObservableList>>(BoxParameter(groupedItemSource)));
					groupContainer->GetContainerComposition()->AddChild(groupStack);
					MenuResetGroupTemplate();
				}

				RequestedScrollUp.AttachMethod(this, &GuiBindableRibbonGalleryList::OnRequestedScrollUp);
				RequestedScrollDown.AttachMethod(this, &GuiBindableRibbonGalleryList::OnRequestedScrollDown);
				RequestedDropdown.AttachMethod(this, &GuiBindableRibbonGalleryList::OnRequestedDropdown);
				boundsComposition->CachedBoundsChanged.AttachMethod(this, &GuiBindableRibbonGalleryList::OnCachedBoundsChanged);
				itemListArranger->UnblockScrollUpdate();
			}

			GuiBindableRibbonGalleryList::~GuiBindableRibbonGalleryList()
			{
				delete subMenu;
			}

			GuiBindableRibbonGalleryList::ItemStyleProperty GuiBindableRibbonGalleryList::GetItemTemplate()
			{
				return itemStyle;
			}

			void GuiBindableRibbonGalleryList::SetItemTemplate(ItemStyleProperty value)
			{
				if (itemStyle != value)
				{
					itemStyle = value;
					itemList->SetItemTemplate(value);
					ItemTemplateChanged.Execute(GetNotifyEventArguments());
				}
			}

			GalleryPos GuiBindableRibbonGalleryList::IndexToGalleryPos(vint index)
			{
				if (0 <= index && index < joinedItemSource.Count())
				{
					for (auto [group, groupIndex] : indexed(groupedItemSource))
					{
						auto itemValues = group->GetItemValues();
						vint itemCount = itemValues ? itemValues->GetCount() : 0;
						if (index >= itemCount)
						{
							index -= itemCount;
						}
						else
						{
							return GalleryPos(groupIndex, index);
						}
					}
				}
				return {};
			}

			vint GuiBindableRibbonGalleryList::GalleryPosToIndex(GalleryPos pos)
			{
				if (0 <= pos.group && pos.group < groupedItemSource.Count())
				{
					auto countBeforeGroup = GetCountBeforeGroup(pos.group);
					auto itemValues = groupedItemSource[pos.group]->GetItemValues();
					vint itemCount = itemValues ? itemValues->GetCount() : 0;
					if (0 <= pos.item && pos.item < itemCount)
					{
						return countBeforeGroup + pos.item;
					}
				}
				return -1;
			}

			vint GuiBindableRibbonGalleryList::GetMinCount()
			{
				return layout->GetMinCount();
			}

			void GuiBindableRibbonGalleryList::SetMinCount(vint value)
			{
				layout->SetMinCount(value);
			}

			vint GuiBindableRibbonGalleryList::GetMaxCount()
			{
				return layout->GetMaxCount();
			}

			void GuiBindableRibbonGalleryList::SetMaxCount(vint value)
			{
				layout->SetMaxCount(value);
			}

			vint GuiBindableRibbonGalleryList::GetSelectedIndex()
			{
				return itemList->GetSelectedItemIndex();
			}

			description::Value GuiBindableRibbonGalleryList::GetSelectedItem()
			{
				vint index = itemList->GetSelectedItemIndex();
				if (index == -1) return Value();

				auto pos = IndexToGalleryPos(index);
				return groupedItemSource[pos.group]->GetItemValues()->Get(pos.item);
			}

			void GuiBindableRibbonGalleryList::ApplyItem(vint index)
			{
				if (index == -1)
				{
					itemList->ClearSelection();
				}
				else
				{
					itemList->SetSelected(index, true);
					itemList->EnsureItemVisible(index);
				}
			}

			void GuiBindableRibbonGalleryList::SelectItem(vint index)
			{
				skipItemAppliedEvent = true;
				ApplyItem(index);
				skipItemAppliedEvent = false;
			}

			vint GuiBindableRibbonGalleryList::GetVisibleItemCount()
			{
				return visibleItemCount;
			}

			void GuiBindableRibbonGalleryList::SetVisibleItemCount(vint value)
			{
				if (visibleItemCount != value)
				{
					visibleItemCount = value;
					UpdateLayoutSizeOffset();
				}
			}

			GuiSelectableListControl* GuiBindableRibbonGalleryList::GetListControlInDropdown()
			{
				return itemList;
			}

			GuiToolstripMenu* GuiBindableRibbonGalleryList::GetSubMenu()
			{
				return subMenu;
			}

			IDescriptable* GuiBindableRibbonGalleryList::QueryService(const WString& identifier)
			{
				if (identifier == IGuiMenuDropdownProvider::Identifier)
				{
					return (IGuiMenuDropdownProvider*)this;
				}
				else
				{
					return GuiRibbonGallery::QueryService(identifier);
				}
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\TOOLSTRIPPACKAGE\GUIRIBBONIMPL.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace compositions;

/***********************************************************************
GalleryItemArrangerRepeatComposition
***********************************************************************/

			namespace ribbon_impl
			{
				void GalleryItemArrangerRepeatComposition::Layout_BeginPlaceItem(bool firstPhase, Rect newBounds, vint& newStartIndex)
				{
					if (firstPhase)
					{
						pim_itemWidth = itemWidth;
						newStartIndex = firstIndex;
					}
				}

				compositions::VirtualRepeatPlaceItemResult GalleryItemArrangerRepeatComposition::Layout_PlaceItem(bool firstPhase, bool newCreatedStyle, vint index, ItemStyleRecord style, Rect viewBounds, Rect& bounds, Margin& alignmentToParent)
				{
					alignmentToParent = Margin(-1, 0, -1, 0);
					bounds = Rect(Point((index - firstIndex) * itemWidth, 0), Size(itemWidth, 0));

					if (firstPhase)
					{
						vint styleWidth = Layout_GetStylePreferredSize(style).x;
						if (pim_itemWidth < styleWidth)
						{
							pim_itemWidth = styleWidth;
						}
					}

					if (bounds.Right() + pim_itemWidth > viewBounds.Right())
					{
						return VirtualRepeatPlaceItemResult::HitLastItem;
					}
					else
					{
						return VirtualRepeatPlaceItemResult::None;
					}
				}

				compositions::VirtualRepeatEndPlaceItemResult GalleryItemArrangerRepeatComposition::Layout_EndPlaceItem(bool firstPhase, Rect newBounds, vint newStartIndex)
				{
					bool result = false;
					if (firstPhase)
					{
						if (pim_itemWidth != itemWidth)
						{
							itemWidth = pim_itemWidth;
							result = true;
						}
					}

					if (!blockScrollUpdate)
					{
						UnblockScrollUpdate();
					}

					return result ?
						VirtualRepeatEndPlaceItemResult::TotalSizeUpdated :
						VirtualRepeatEndPlaceItemResult::None;
				}

				void GalleryItemArrangerRepeatComposition::Layout_EndLayout(bool totalSizeUpdated)
				{
				}

				void GalleryItemArrangerRepeatComposition::Layout_InvalidateItemSizeCache()
				{
					itemWidth = 1;
				}

				void GalleryItemArrangerRepeatComposition::Layout_CalculateTotalSize(Size& full, Size& minimum)
				{
					full = Size(1, 1);
					minimum = Size(1, 1);
				}

				Size GalleryItemArrangerRepeatComposition::Layout_GetAdoptedSize(Size expectedSize)
				{
					return Size(1, 1);
				}

				GalleryItemArrangerRepeatComposition::GalleryItemArrangerRepeatComposition(GuiBindableRibbonGalleryList* _owner)
					:owner(_owner)
				{
				}

				GalleryItemArrangerRepeatComposition::~GalleryItemArrangerRepeatComposition()
				{
				}

				vint GalleryItemArrangerRepeatComposition::FindItemByVirtualKeyDirection(vint itemIndex, compositions::KeyDirection key)
				{
					vint count = itemSource->GetCount();
					if (itemIndex < 0 || itemIndex >= count) return -1;
					vint groupCount = viewBounds.Width() / itemWidth;
					if (groupCount == 0) groupCount = 1;

					switch (key)
					{
					case KeyDirection::Left:
						itemIndex--;
						break;
					case KeyDirection::Right:
						itemIndex++;
						break;
					case KeyDirection::Home:
						itemIndex = 0;
						break;
					case KeyDirection::End:
						itemIndex = count;
						break;
					case KeyDirection::PageUp:
						itemIndex -= groupCount;
						break;
					case KeyDirection::PageDown:
						itemIndex += groupCount;
						break;
					default:
						return -1;
					}

					if (itemIndex < 0) return 0;
					else if (itemIndex >= count) return count - 1;
					else return itemIndex;
				}

				compositions::VirtualRepeatEnsureItemVisibleResult GalleryItemArrangerRepeatComposition::EnsureItemVisible(vint itemIndex)
				{
					if (!itemSource) return VirtualRepeatEnsureItemVisibleResult::NotMoved;
					if (itemIndex < 0 || itemIndex >= itemSource->GetCount())
					{
						return VirtualRepeatEnsureItemVisibleResult::ItemNotExists;
					}

					vint groupCount = viewBounds.Width() / itemWidth;
					if (groupCount == 0) groupCount = 1;

					if (itemIndex < firstIndex)
					{
						firstIndex = itemIndex;
						InvalidateLayout();
					}
					else if (itemIndex >= firstIndex + groupCount)
					{
						firstIndex = itemIndex - groupCount + 1;
						InvalidateLayout();
					}
					return VirtualRepeatEnsureItemVisibleResult::NotMoved;
				}

				void GalleryItemArrangerRepeatComposition::ScrollUp()
				{
					vint count = itemSource->GetCount();
					vint groupCount = viewBounds.Width() / itemWidth;
					if (groupCount == 0) groupCount = 1;

					if (count > groupCount)
					{
						firstIndex -= groupCount;
						if (firstIndex < 0)
						{
							firstIndex = 0;
						}
						InvalidateLayout();
					}
				}

				void GalleryItemArrangerRepeatComposition::ScrollDown()
				{
					vint count = itemSource->GetCount();
					vint groupCount = viewBounds.Width() / itemWidth;
					if (groupCount == 0) groupCount = 1;

					if (count > groupCount)
					{
						firstIndex += groupCount;
						if (firstIndex > count - groupCount)
						{
							firstIndex = count - groupCount;
						}
						InvalidateLayout();
					}
				}

				void GalleryItemArrangerRepeatComposition::UnblockScrollUpdate()
				{
					blockScrollUpdate = false;

					vint count = itemSource->GetCount();
					vint groupCount = viewBounds.Width() / pim_itemWidth;
					if (groupCount == 0) groupCount = 1;

					owner->SetScrollUpEnabled(firstIndex > 0);
					owner->SetScrollDownEnabled(firstIndex + groupCount < count);
					if (owner->layout->GetItemWidth() != pim_itemWidth)
					{
						owner->layout->SetItemWidth(pim_itemWidth);
						owner->UpdateLayoutSizeOffset();
					}
				}

/***********************************************************************
GalleryItemArranger
***********************************************************************/

				GalleryItemArranger::GalleryItemArranger(GuiBindableRibbonGalleryList* _owner)
					: TBase(new TBase::ArrangerRepeatComposition(this, _owner))
				{
				}

				GalleryItemArranger::~GalleryItemArranger()
				{
				}
				
				void GalleryItemArranger::ScrollUp()
				{
					GetRepeatComposition()->ScrollUp();
				}

				void GalleryItemArranger::ScrollDown()
				{
					GetRepeatComposition()->ScrollDown();
				}

				void GalleryItemArranger::UnblockScrollUpdate()
				{
					GetRepeatComposition()->UnblockScrollUpdate();
				}

/***********************************************************************
GalleryResponsiveLayout
***********************************************************************/

				void GalleryResponsiveLayout::UpdateMinSize()
				{
					SetPreferredMinSize(Size(itemCount * itemWidth + sizeOffset.x, sizeOffset.y));
				}

				GalleryResponsiveLayout::GalleryResponsiveLayout()
				{
					SetDirection(ResponsiveDirection::Horizontal);
				}

				GalleryResponsiveLayout::~GalleryResponsiveLayout()
				{
				}

				vint GalleryResponsiveLayout::GetMinCount()
				{
					return minCount;
				}

				vint GalleryResponsiveLayout::GetMaxCount()
				{
					return maxCount;
				}

				vint GalleryResponsiveLayout::GetItemWidth()
				{
					return itemWidth;
				}

				Size GalleryResponsiveLayout::GetSizeOffset()
				{
					return sizeOffset;
				}

				vint GalleryResponsiveLayout::GetVisibleItemCount()
				{
					return itemCount;
				}

				void GalleryResponsiveLayout::SetMinCount(vint value)
				{
					vint oldCount = GetLevelCount();
					vint oldLevel = GetCurrentLevel();

					if (minCount != value)
					{
						if (value < 0) value = 0;
						minCount = value;
						if (maxCount < minCount) maxCount = minCount;
						if (itemCount < minCount) itemCount = minCount;
						UpdateMinSize();
					}

					bool countChanged = oldCount != GetLevelCount();
					bool levelChanged = oldLevel != GetCurrentLevel();
					if (countChanged) LevelCountChanged.Execute(GuiEventArgs(this));
					if (levelChanged) CurrentLevelChanged.Execute(GuiEventArgs(this));
					if (countChanged || levelChanged) OnResponsiveChildLevelUpdated();
				}

				void GalleryResponsiveLayout::SetMaxCount(vint value)
				{
					vint oldCount = GetLevelCount();
					vint oldLevel = GetCurrentLevel();

					if (maxCount != value)
					{
						if (value < 0) value = 0;
						maxCount = value;
						if (minCount > maxCount) minCount = maxCount;
						if (itemCount > maxCount) itemCount = maxCount;
						UpdateMinSize();
					}

					if (oldCount != GetLevelCount()) LevelCountChanged.Execute(GuiEventArgs(this));
					if (oldLevel != GetCurrentLevel()) CurrentLevelChanged.Execute(GuiEventArgs(this));
				}

				void GalleryResponsiveLayout::SetItemWidth(vint value)
				{
					if (itemWidth != value)
					{
						itemWidth = value;
						UpdateMinSize();
					}
				}

				void GalleryResponsiveLayout::SetSizeOffset(Size value)
				{
					if (sizeOffset != value)
					{
						sizeOffset = value;
						UpdateMinSize();
					}
				}

				vint GalleryResponsiveLayout::GetLevelCount()
				{
					return maxCount - minCount + 1;
				}

				vint GalleryResponsiveLayout::GetCurrentLevel()
				{
					return itemCount - minCount;
				}

				bool GalleryResponsiveLayout::LevelDown()
				{
					if (itemCount > minCount)
					{
						itemCount--;
						UpdateMinSize();
						CurrentLevelChanged.Execute(GuiEventArgs(this));
						return true;
					}
					return false;
				}

				bool GalleryResponsiveLayout::LevelUp()
				{
					if (itemCount < maxCount)
					{
						itemCount++;
						UpdateMinSize();
						CurrentLevelChanged.Execute(GuiEventArgs(this));
						return true;
					}
					return false;
				}
			}
		}
	}
}

/***********************************************************************
.\CONTROLS\TOOLSTRIPPACKAGE\GUITOOLSTRIPCOMMAND.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace collections;
			using namespace compositions;
			using namespace regex;

/***********************************************************************
GuiToolstripCommand
***********************************************************************/

			void GuiToolstripCommand::OnShortcutKeyItemExecuted(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (enabled)
				{
					Executed.ExecuteWithNewSender(arguments, sender);
				}
			}

			void GuiToolstripCommand::OnRenderTargetChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				UpdateShortcutOwner();
			}

			void GuiToolstripCommand::InvokeDescriptionChanged()
			{
				GuiEventArgs arguments;
				DescriptionChanged.Execute(arguments);
			}

			compositions::IGuiShortcutKeyManager* GuiToolstripCommand::GetShortcutManagerFromBuilder(Ptr<ShortcutBuilder> builder)
			{
				if (builder->global)
				{
					return GetApplication()->GetGlobalShortcutKeyManager();
				}
				else
				{
					if (attachedControlHost)
					{
						if (!attachedControlHost->GetShortcutKeyManager())
						{
							attachedControlHost->SetShortcutKeyManager(new GuiShortcutKeyManager());
						}
						return attachedControlHost->GetShortcutKeyManager();
					}
				}
				return nullptr;
			}

			void GuiToolstripCommand::RemoveShortcut()
			{
				if (shortcutKeyItem)
				{
					shortcutKeyItem->Executed.Detach(shortcutKeyItemExecutedHandler);
					shortcutKeyItem->GetManager()->DestroyShortcut(shortcutKeyItem);
				}
				shortcutKeyItem = nullptr;
				shortcutKeyItemExecutedHandler = nullptr;
			}

			void GuiToolstripCommand::ReplaceShortcut(compositions::IGuiShortcutKeyItem* value)
			{
				if (shortcutKeyItem != value)
				{
					RemoveShortcut();
					if (value)
					{
						shortcutKeyItem = value;
						shortcutKeyItemExecutedHandler = shortcutKeyItem->Executed.AttachMethod(this, &GuiToolstripCommand::OnShortcutKeyItemExecuted);
					}
					InvokeDescriptionChanged();
				}
			}

			void GuiToolstripCommand::BuildShortcut(const WString& builderText)
			{
				List<glr::ParsingError> errors;
				if (auto parser = GetParserManager()->GetParser<ShortcutBuilder>(L"SHORTCUT"))
				{
					if (auto builder = parser->ParseInternal(builderText, errors))
					{
						shortcutBuilder = builder;
						if (auto shortcutKeyManager = GetShortcutManagerFromBuilder(builder))
						{
							if (auto item = shortcutKeyManager->CreateShortcutIfNotExist(builder->ctrl, builder->shift, builder->alt, builder->key))
							{
								ReplaceShortcut(item);
							}
						}
					}
				}
			}

			void GuiToolstripCommand::UpdateShortcutOwner()
			{
				GuiControlHost* host = nullptr;
				if (auto control = dynamic_cast<GuiControl*>(attachedRootObject))
				{
					host = control->GetRelatedControlHost();
				}
				else if (auto composition = dynamic_cast<GuiGraphicsComposition*>(attachedRootObject))
				{
					host = composition->GetRelatedControlHost();
				}

				if (attachedControlHost != host)
				{
					attachedControlHost = host;
					if (shortcutBuilder && !shortcutBuilder->global)
					{
						if (shortcutKeyItem)
						{
							ReplaceShortcut(nullptr);
						}
						BuildShortcut(shortcutBuilder->text);
					}
				}
			}

			GuiToolstripCommand::GuiToolstripCommand()
			{
			}

			GuiToolstripCommand::~GuiToolstripCommand()
			{
				RemoveShortcut();
				shortcutBuilder = nullptr;
			}

			void GuiToolstripCommand::Attach(GuiInstanceRootObject* rootObject)
			{
				GuiGraphicsComposition* rootComposition = nullptr;

				if (attachedRootObject != rootObject)
				{
					if (attachedRootObject)
					{
						if (auto control = dynamic_cast<GuiControl*>(attachedRootObject))
						{
							control->ControlSignalTrigerred.Detach(renderTargetChangedHandler);
						}
						else if (auto composition = dynamic_cast<GuiGraphicsComposition*>(attachedRootObject))
						{
							composition->GetEventReceiver()->renderTargetChanged.Detach(renderTargetChangedHandler);
						}
						renderTargetChangedHandler = nullptr;
					}

					attachedRootObject = rootObject;
					if (attachedRootObject)
					{
						if (auto control = dynamic_cast<GuiControl*>(attachedRootObject))
						{
							renderTargetChangedHandler = control->ControlSignalTrigerred.AttachLambda(
								[=, this](GuiGraphicsComposition* sender, GuiControlSignalEventArgs& arguments)
								{
									OnRenderTargetChanged(sender, arguments);
								});
						}
						else if (auto composition = dynamic_cast<GuiGraphicsComposition*>(attachedRootObject))
						{
							renderTargetChangedHandler = composition->GetEventReceiver()->renderTargetChanged.AttachMethod(this, &GuiToolstripCommand::OnRenderTargetChanged);
						}
					}
					UpdateShortcutOwner();
				}
			}

			void GuiToolstripCommand::Detach(GuiInstanceRootObject* rootObject)
			{
				Attach(nullptr);
			}

			Ptr<GuiImageData> GuiToolstripCommand::GetLargeImage()
			{
				return largeImage;
			}

			void GuiToolstripCommand::SetLargeImage(Ptr<GuiImageData> value)
			{
				if (largeImage != value)
				{
					largeImage = value;
					InvokeDescriptionChanged();
				}
			}

			Ptr<GuiImageData> GuiToolstripCommand::GetImage()
			{
				return image;
			}

			void GuiToolstripCommand::SetImage(Ptr<GuiImageData> value)
			{
				if(image!=value)
				{
					image=value;
					InvokeDescriptionChanged();
				}
			}

			const WString& GuiToolstripCommand::GetText()
			{
				return text;
			}

			void GuiToolstripCommand::SetText(const WString& value)
			{
				if(text!=value)
				{
					text=value;
					InvokeDescriptionChanged();
				}
			}

			compositions::IGuiShortcutKeyItem* GuiToolstripCommand::GetShortcut()
			{
				return shortcutKeyItem;
			}

			WString GuiToolstripCommand::GetShortcutBuilder()
			{
				return shortcutBuilder ? shortcutBuilder->text : L"";
			}

			void GuiToolstripCommand::SetShortcutBuilder(const WString& value)
			{
				BuildShortcut(value);
			}

			bool GuiToolstripCommand::GetEnabled()
			{
				return enabled;
			}

			void GuiToolstripCommand::SetEnabled(bool value)
			{
				if(enabled!=value)
				{
					enabled=value;
					InvokeDescriptionChanged();
				}
			}

			bool GuiToolstripCommand::GetSelected()
			{
				return selected;
			}

			void GuiToolstripCommand::SetSelected(bool value)
			{
				if(selected!=value)
				{
					selected=value;
					InvokeDescriptionChanged();
				}
			}

/***********************************************************************
GuiToolstripCommand::ShortcutBuilder Parser
***********************************************************************/

			class GuiToolstripCommandShortcutParser : public Object, public IGuiParser<GuiToolstripCommand::ShortcutBuilder>
			{
				typedef GuiToolstripCommand::ShortcutBuilder			ShortcutBuilder;
			public:
				Regex						regexShortcut;
				const vint					_global;
				const vint					_ctrl;
				const vint					_shift;
				const vint					_alt;
				const vint					_key;

				GuiToolstripCommandShortcutParser()
					: regexShortcut(L"((<global>global:))?((<ctrl>Ctrl)/+|(<shift>Shift)/+|(<alt>Alt)/+)*(<key>/.+)")
					, _global(regexShortcut.CaptureNames().IndexOf(L"global"))
					, _ctrl(regexShortcut.CaptureNames().IndexOf(L"ctrl"))
					, _shift(regexShortcut.CaptureNames().IndexOf(L"shift"))
					, _alt(regexShortcut.CaptureNames().IndexOf(L"alt"))
					, _key(regexShortcut.CaptureNames().IndexOf(L"key"))
				{
				}

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

					auto builder = Ptr(new ShortcutBuilder);
					builder->text = text;
					builder->global = match->Groups().Contains(_global);
					builder->ctrl = match->Groups().Contains(_ctrl);
					builder->shift = match->Groups().Contains(_shift);
					builder->alt = match->Groups().Contains(_alt);

					WString name = match->Groups()[_key][0].Value();
					builder->key = GetCurrentController()->InputService()->GetKey(name);

					return builder->key == VKEY::KEY_UNKNOWN ? nullptr : builder;
				}
			};

/***********************************************************************
GuiToolstripCommandPlugin
***********************************************************************/

			class GuiToolstripCommandPlugin : public Object, public IGuiPlugin
			{
			public:

				GUI_PLUGIN_NAME(GacUI_Compiler_ShortcutParser)
				{
					GUI_PLUGIN_DEPEND(GacUI_Parser);
				}
				
				void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
				{
					if (controllerUnrelatedPlugins)
					{
						IGuiParserManager* manager = GetParserManager();
						manager->SetParser(L"SHORTCUT", Ptr(new GuiToolstripCommandShortcutParser));
					}
				}

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

/***********************************************************************
.\CONTROLS\TOOLSTRIPPACKAGE\GUITOOLSTRIPMENU.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace controls
		{
			using namespace collections;
			using namespace compositions;

/***********************************************************************
GuiToolstripCollectionBase
***********************************************************************/

			const wchar_t* const IToolstripUpdateLayoutInvoker::Identifier = L"vl::presentation::controls::IToolstripUpdateLayoutInvoker";

			void GuiToolstripCollectionBase::InvokeUpdateLayout()
			{
				if(contentCallback)
				{
					contentCallback->UpdateLayout();
				}
			}

			bool GuiToolstripCollectionBase::QueryInsert(vint index, GuiControl* const& child)
			{
				return !items.Contains(child) && !child->GetBoundsComposition()->GetParent();
			}

			void GuiToolstripCollectionBase::BeforeRemove(vint index, GuiControl* const& child)
			{
				if (auto invoker = child->QueryTypedService<IToolstripUpdateLayoutInvoker>())
				{
					invoker->SetCallback(nullptr);
				}
				InvokeUpdateLayout();
			}

			void GuiToolstripCollectionBase::AfterInsert(vint index, GuiControl* const& child)
			{
				if (auto invoker = child->QueryTypedService<IToolstripUpdateLayoutInvoker>())
				{
					invoker->SetCallback(contentCallback);
				}
				InvokeUpdateLayout();
			}

			void GuiToolstripCollectionBase::AfterRemove(vint index, vint count)
			{
				InvokeUpdateLayout();
			}

			GuiToolstripCollectionBase::GuiToolstripCollectionBase(IToolstripUpdateLayout* _contentCallback)
				:contentCallback(_contentCallback)
			{
			}

			GuiToolstripCollectionBase::~GuiToolstripCollectionBase()
			{
			}

/***********************************************************************
GuiToolstripCollection
***********************************************************************/

			void GuiToolstripCollection::UpdateItemVisibility(vint index, GuiControl* child)
			{
				auto stackItem = stackComposition->GetStackItems()[index];
				if (child->GetVisible())
				{
					stackItem->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
					child->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
				}
				else
				{
					stackItem->SetMinSizeLimitation(GuiGraphicsComposition::NoLimit);
					child->GetBoundsComposition()->SetAlignmentToParent(Margin(-1, -1, -1, -1));
				}
			}

			void GuiToolstripCollection::OnItemVisibleChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				auto child = sender->GetRelatedControl();
				vint index = IndexOf(child);
				UpdateItemVisibility(index, child);
				InvokeUpdateLayout();
			}

			void GuiToolstripCollection::BeforeRemove(vint index, GuiControl* const& child)
			{
				GuiStackItemComposition* stackItem = stackComposition->GetStackItems().Get(index);

				auto eventHandler = eventHandlers[index];
				child->VisibleChanged.Detach(eventHandler);
				eventHandlers.RemoveAt(index);

				GuiToolstripCollectionBase::BeforeRemove(index, child);
			}

			void GuiToolstripCollection::AfterInsert(vint index, GuiControl* const& child)
			{
				{
					GuiStackItemComposition* stackItem = new GuiStackItemComposition;
					stackItem->AddChild(child->GetBoundsComposition());
					stackComposition->InsertStackItem(index, stackItem);
				}
				{
					auto eventHandler = child->VisibleChanged.AttachMethod(this, &GuiToolstripCollection::OnItemVisibleChanged);
					eventHandlers.Insert(index, eventHandler);
				}
				UpdateItemVisibility(index, child);
				GuiToolstripCollectionBase::AfterInsert(index, child);
			}

			void GuiToolstripCollection::AfterRemove(vint index, vint count)
			{
				for (vint i = 0; i < count; i++)
				{
					auto stackItem = stackComposition->GetStackItems().Get(index);
					stackComposition->RemoveChild(stackItem);
					SafeDeleteComposition(stackItem);
				}
				GuiToolstripCollectionBase::AfterRemove(index, count);
			}

			GuiToolstripCollection::GuiToolstripCollection(IToolstripUpdateLayout* _contentCallback, compositions::GuiStackComposition* _stackComposition)
				:GuiToolstripCollectionBase(_contentCallback)
				,stackComposition(_stackComposition)
			{
				stackComposition->SetPreferredMinSize(Size(1, 1));
			}

			GuiToolstripCollection::~GuiToolstripCollection()
			{
			}

/***********************************************************************
GuiToolstripMenu
***********************************************************************/

			void GuiToolstripMenu::UpdateLayout()
			{
				sharedSizeRootComposition->ForceCalculateSizeImmediately();
			}

			GuiToolstripMenu::GuiToolstripMenu(theme::ThemeName themeName, GuiControl* _owner)
				:GuiMenu(themeName, _owner)
			{
				sharedSizeRootComposition = new GuiSharedSizeRootComposition();
				sharedSizeRootComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				sharedSizeRootComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				containerComposition->AddChild(sharedSizeRootComposition);

				stackComposition=new GuiStackComposition;
				stackComposition->SetDirection(GuiStackComposition::Vertical);
				stackComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				stackComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				sharedSizeRootComposition->AddChild(stackComposition);
				
				toolstripItems = Ptr(new GuiToolstripCollection(this, stackComposition));
			}

			GuiToolstripMenu::~GuiToolstripMenu()
			{
			}

			collections::ObservableListBase<GuiControl*>& GuiToolstripMenu::GetToolstripItems()
			{
				return *toolstripItems.Obj();
			}

/***********************************************************************
GuiToolstripMenuBar
***********************************************************************/
			
			GuiToolstripMenuBar::GuiToolstripMenuBar(theme::ThemeName themeName)
				:GuiMenuBar(themeName)
			{
				stackComposition=new GuiStackComposition;
				stackComposition->SetDirection(GuiStackComposition::Horizontal);
				stackComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				stackComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				containerComposition->AddChild(stackComposition);

				toolstripItems=Ptr(new GuiToolstripCollection(nullptr, stackComposition));
			}

			GuiToolstripMenuBar::~GuiToolstripMenuBar()
			{
			}

			collections::ObservableListBase<GuiControl*>& GuiToolstripMenuBar::GetToolstripItems()
			{
				return *toolstripItems.Obj();
			}

/***********************************************************************
GuiToolstripToolBar
***********************************************************************/

			IGuiMenuService* GuiToolstripToolBar::GetParentMenuService()
			{
				return GetParent() ? GetParent()->QueryTypedService<IGuiMenuService>() : nullptr;
			}

			IGuiMenuService::Direction GuiToolstripToolBar::GetPreferredDirection()
			{
				return IGuiMenuService::Horizontal;
			}

			theme::ThemeName GuiToolstripToolBar::GetHostThemeName()
			{
				return GetControlThemeName();
			}

			bool GuiToolstripToolBar::IsActiveState()
			{
				return GetOpeningMenu() != nullptr;
			}

			bool GuiToolstripToolBar::IsSubMenuActivatedByMouseDown()
			{
				return false;
			}
				
			GuiToolstripToolBar::GuiToolstripToolBar(theme::ThemeName themeName)
				:GuiControl(themeName)
			{
				stackComposition=new GuiStackComposition;
				stackComposition->SetDirection(GuiStackComposition::Horizontal);
				stackComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				stackComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				containerComposition->AddChild(stackComposition);

				toolstripItems=Ptr(new GuiToolstripCollection(nullptr, stackComposition));
			}

			GuiToolstripToolBar::~GuiToolstripToolBar()
			{
			}

			collections::ObservableListBase<GuiControl*>& GuiToolstripToolBar::GetToolstripItems()
			{
				return *toolstripItems.Obj();
			}

			IDescriptable* GuiToolstripToolBar::QueryService(const WString& identifier)
			{
				if (identifier == IGuiMenuService::Identifier)
				{
					return (IGuiMenuService*)this;
				}
				else
				{
					return GuiControl::QueryService(identifier);
				}
			}

/***********************************************************************
GuiToolstripButton
***********************************************************************/

			void GuiToolstripButton::SetCallback(IToolstripUpdateLayout* _callback)
			{
				callback = _callback;
			}

			void GuiToolstripButton::OnActiveAlt()
			{
				auto host = GetSubMenuHost();
				if (host == this)
				{
					GuiMenuButton::OnActiveAlt();
				}
				else
				{
					host->QueryTypedService<IGuiAltAction>()->OnActiveAlt();
				}
			}

			void GuiToolstripButton::UpdateCommandContent()
			{
				if(command)
				{
					SetLargeImage(command->GetLargeImage());
					SetImage(command->GetImage());
					SetText(command->GetText());
					SetEnabled(command->GetEnabled());
					SetSelected(command->GetSelected());
					if(command->GetShortcut())
					{
						SetShortcutText(command->GetShortcut()->GetName());
					}
					else
					{
						SetShortcutText(L"");
					}
				}
				else
				{
					SetLargeImage(nullptr);
					SetImage(nullptr);
					SetText(L"");
					SetEnabled(true);
					SetSelected(false);
					SetShortcutText(L"");
				}
			}

			void GuiToolstripButton::OnLayoutAwaredPropertyChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if (callback)
				{
					callback->UpdateLayout();
				}
			}

			void GuiToolstripButton::OnClicked(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				if(command)
				{
					command->Executed.ExecuteWithNewSender(arguments, sender);
				}
			}

			void GuiToolstripButton::OnCommandDescriptionChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments)
			{
				UpdateCommandContent();
			}

			GuiToolstripButton::GuiToolstripButton(theme::ThemeName themeName)
				:GuiMenuButton(themeName)
				,command(0)
			{
				SetAutoFocus(false);
				Clicked.AttachMethod(this, &GuiToolstripButton::OnClicked);
				TextChanged.AttachMethod(this, &GuiToolstripButton::OnLayoutAwaredPropertyChanged);
				ShortcutTextChanged.AttachMethod(this, &GuiToolstripButton::OnLayoutAwaredPropertyChanged);
			}

			GuiToolstripButton::~GuiToolstripButton()
			{
			}

			GuiToolstripCommand* GuiToolstripButton::GetCommand()
			{
				return command;
			}

			void GuiToolstripButton::SetCommand(GuiToolstripCommand* value)
			{
				if(command!=value)
				{
					if(command)
					{
						command->DescriptionChanged.Detach(descriptionChangedHandler);
					}
					command=0;
					descriptionChangedHandler=0;
					if(value)
					{
						command=value;
						descriptionChangedHandler=command->DescriptionChanged.AttachMethod(this, &GuiToolstripButton::OnCommandDescriptionChanged);
					}
					UpdateCommandContent();
				}
			}

			GuiToolstripMenu* GuiToolstripButton::GetToolstripSubMenu()
			{
				return dynamic_cast<GuiToolstripMenu*>(GetSubMenu());
			}

			GuiToolstripMenu* GuiToolstripButton::EnsureToolstripSubMenu()
			{
				if (!GetSubMenu())
				{
					CreateToolstripSubMenu({});
				}
				return dynamic_cast<GuiToolstripMenu*>(GetSubMenu());
			}

			void GuiToolstripButton::CreateToolstripSubMenu(TemplateProperty<templates::GuiMenuTemplate> subMenuTemplate)
			{
				if (!subMenu)
				{
					auto newSubMenu = new GuiToolstripMenu(theme::ThemeName::Menu, this);
					if (subMenuTemplate)
					{
						newSubMenu->SetControlTemplate(subMenuTemplate);
					}
					else
					{
						newSubMenu->SetControlTemplate(TypedControlTemplateObject(true)->GetSubMenuTemplate());
					}
					SetSubMenu(newSubMenu, true);
				}
			}

			IDescriptable* GuiToolstripButton::QueryService(const WString& identifier)
			{
				if (identifier == IToolstripUpdateLayoutInvoker::Identifier)
				{
					return (IToolstripUpdateLayoutInvoker*)this;
				}
				else
				{
					return GuiMenuButton::QueryService(identifier);
				}
			}

/***********************************************************************
GuiToolstripNestedContainer
***********************************************************************/

			void GuiToolstripNestedContainer::UpdateLayout()
			{
				// It could happen if a GuiToolstripGroupContainer contains something other that GuiToolstripGroup
				if (callback && callback != this)
				{
					callback->UpdateLayout();
				}
			}

			void GuiToolstripNestedContainer::SetCallback(IToolstripUpdateLayout* _callback)
			{
				callback = _callback;
			}

			GuiToolstripNestedContainer::GuiToolstripNestedContainer(theme::ThemeName themeName)
				:GuiControl(themeName)
			{
			}

			GuiToolstripNestedContainer::~GuiToolstripNestedContainer()
			{
			}

			IDescriptable* GuiToolstripNestedContainer::QueryService(const WString& identifier)
			{
				if (identifier == IToolstripUpdateLayoutInvoker::Identifier)
				{
					return (IToolstripUpdateLayoutInvoker*)this;
				}
				else
				{
					return GuiControl::QueryService(identifier);
				}
			}

/***********************************************************************
GuiToolstripGroupContainer::GroupCollection
***********************************************************************/

			void GuiToolstripGroupContainer::GroupCollection::BeforeRemove(vint index, GuiControl* const& child)
			{
				auto controlStackItem = container->stackComposition->GetStackItems()[index * 2];
				CHECK_ERROR(controlStackItem->RemoveChild(child->GetBoundsComposition()), L"GuiToolstripGroupContainer::GroupCollection::BeforeRemove(vint, GuiControl* const&)#Internal error");
			}

			void GuiToolstripGroupContainer::GroupCollection::AfterInsert(vint index, GuiControl* const& child)
			{
				auto controlStackItem = new GuiStackItemComposition;
				child->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
				CHECK_ERROR(controlStackItem->AddChild(child->GetBoundsComposition()), L"GuiToolstripGroupContainer::GroupCollection::AfterInsert(vint, GuiControl* const&)#Internal error");

				if (container->stackComposition->GetStackItems().Count() > 0)
				{
					auto splitterStackItem = new GuiStackItemComposition;
					auto splitter = new GuiControl(container->splitterThemeName);
					if (splitterTemplate)
					{
						splitter->SetControlTemplate(splitterTemplate);
					}
					splitter->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
					splitterStackItem->AddChild(splitter->GetBoundsComposition());
					container->stackComposition->InsertStackItem(index == 0 ? 0 : index * 2 - 1, splitterStackItem);
				}

				container->stackComposition->InsertStackItem(index * 2, controlStackItem);

				GuiToolstripCollectionBase::AfterInsert(index, child);
			}

			void GuiToolstripGroupContainer::GroupCollection::AfterRemove(vint index, vint count)
			{
				vint min = index * 2;
				vint max = (index + count - 1) * 2;
				for (vint i = min; i <= max; i++)
				{
					auto stackItem = container->stackComposition->GetStackItems()[min];
					container->stackComposition->RemoveChild(stackItem);
					SafeDeleteComposition(stackItem);
				}
				GuiToolstripCollectionBase::AfterRemove(index, count);
			}

			GuiToolstripGroupContainer::GroupCollection::GroupCollection(GuiToolstripGroupContainer* _container)
				:GuiToolstripCollectionBase(_container)
				, container(_container)
			{
			}

			GuiToolstripGroupContainer::GroupCollection::~GroupCollection()
			{
			}

			GuiToolstripGroupContainer::ControlTemplatePropertyType GuiToolstripGroupContainer::GroupCollection::GetSplitterTemplate()
			{
				return splitterTemplate;
			}

			void GuiToolstripGroupContainer::GroupCollection::SetSplitterTemplate(const ControlTemplatePropertyType& value)
			{
				splitterTemplate = value;
				RebuildSplitters();
			}

			void GuiToolstripGroupContainer::GroupCollection::RebuildSplitters()
			{
				auto stack = container->stackComposition;
				vint count = stack->GetStackItems().Count();
				for (vint i = 1; i < count; i += 2)
				{
					auto stackItem = stack->GetStackItems()[i];
					{
						auto control = stackItem->Children()[0]->GetAssociatedControl();
						CHECK_ERROR(control != nullptr, L"GuiToolstripGroupContainer::GroupCollection::RebuildSplitters()#Internal error");
						stackItem->RemoveChild(control->GetBoundsComposition());
						delete control;
					}
					{
						auto control = new GuiControl(container->splitterThemeName);
						if (splitterTemplate)
						{
							control->SetControlTemplate(splitterTemplate);
						}
						control->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
						stackItem->AddChild(control->GetBoundsComposition());
					}
				}
			}

/***********************************************************************
GuiToolstripGroupContainer
***********************************************************************/

			void GuiToolstripGroupContainer::OnParentLineChanged()
			{
				auto newDirection = GuiStackComposition::Horizontal;
				auto newTheme = theme::ThemeName::ToolstripSplitter;

				if (auto service = QueryTypedService<IGuiMenuService>())
				{
					if (service->GetPreferredDirection() == IGuiMenuService::Vertical)
					{
						newTheme = theme::ThemeName::MenuSplitter;
						newDirection = GuiStackComposition::Vertical;
					}

					switch (service->GetHostThemeName())
					{
					case theme::ThemeName::MenuBar:
						newTheme = theme::ThemeName::MenuSplitter;
						break;
					case theme::ThemeName::ToolstripToolBar:
						newTheme = theme::ThemeName::ToolstripSplitter;
						break;
					case theme::ThemeName::ToolstripToolBarInMenu:
						newTheme = theme::ThemeName::ToolstripSplitterInMenu;
						break;
					default:;
					}
				}

				if (newDirection != stackComposition->GetDirection() || newTheme != splitterThemeName)
				{
					splitterThemeName = newTheme;
					stackComposition->SetDirection(newDirection);
					groupCollection->RebuildSplitters();
					UpdateLayout();
				}

				GuiControl::OnParentLineChanged();
			}

			GuiToolstripGroupContainer::GuiToolstripGroupContainer(theme::ThemeName themeName)
				:GuiToolstripNestedContainer(themeName)
				, splitterThemeName(theme::ThemeName::ToolstripSplitter)
			{
				stackComposition = new GuiStackComposition;
				stackComposition->SetDirection(GuiStackComposition::Horizontal);
				stackComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				stackComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				containerComposition->AddChild(stackComposition);

				groupCollection = Ptr(new GroupCollection(this));
			}

			GuiToolstripGroupContainer::~GuiToolstripGroupContainer()
			{
			}

			GuiToolstripGroupContainer::ControlTemplatePropertyType GuiToolstripGroupContainer::GetSplitterTemplate()
			{
				return groupCollection->GetSplitterTemplate();
			}

			void GuiToolstripGroupContainer::SetSplitterTemplate(const ControlTemplatePropertyType& value)
			{
				groupCollection->SetSplitterTemplate(value);
			}

			collections::ObservableListBase<GuiControl*>& GuiToolstripGroupContainer::GetToolstripItems()
			{
				return *groupCollection.Obj();
			}

/***********************************************************************
GuiToolstripGroup
***********************************************************************/

			void GuiToolstripGroup::OnParentLineChanged()
			{
				auto direction = GuiStackComposition::Horizontal;
				if (auto service = QueryTypedService<IGuiMenuService>())
				{
					if (service->GetPreferredDirection() == IGuiMenuService::Vertical)
					{
						direction = GuiStackComposition::Vertical;
					}
				}

				if (direction != stackComposition->GetDirection())
				{
					stackComposition->SetDirection(direction);
					UpdateLayout();
				}

				GuiControl::OnParentLineChanged();
			}

			GuiToolstripGroup::GuiToolstripGroup(theme::ThemeName themeName)
				:GuiToolstripNestedContainer(themeName)
			{
				stackComposition = new GuiStackComposition;
				stackComposition->SetDirection(GuiStackComposition::Horizontal);
				stackComposition->SetAlignmentToParent(Margin(0, 0, 0, 0));
				stackComposition->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				containerComposition->AddChild(stackComposition);

				toolstripItems = Ptr(new GuiToolstripCollection(nullptr, stackComposition));
			}

			GuiToolstripGroup::~GuiToolstripGroup()
			{
			}

			collections::ObservableListBase<GuiControl*>& GuiToolstripGroup::GetToolstripItems()
			{
				return *toolstripItems.Obj();
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSCOMPOSITION\GUIGRAPHICSAXIS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{

/***********************************************************************
GuiDefaultAxis
***********************************************************************/

			GuiDefaultAxis::GuiDefaultAxis()
			{
			}

			GuiDefaultAxis::~GuiDefaultAxis()
			{
			}

			Size GuiDefaultAxis::RealSizeToVirtualSize(Size size)
			{
				return size;
			}

			Size GuiDefaultAxis::VirtualSizeToRealSize(Size size)
			{
				return size;
			}

			Point GuiDefaultAxis::RealPointToVirtualPoint(Size realFullSize, Point point)
			{
				return point;
			}

			Point GuiDefaultAxis::VirtualPointToRealPoint(Size realFullSize, Point point)
			{
				return point;
			}

			Rect GuiDefaultAxis::RealRectToVirtualRect(Size realFullSize, Rect rect)
			{
				return rect;
			}

			Rect GuiDefaultAxis::VirtualRectToRealRect(Size realFullSize, Rect rect)
			{
				return rect;
			}

			Margin GuiDefaultAxis::RealMarginToVirtualMargin(Margin margin)
			{
				return margin;
			}

			Margin GuiDefaultAxis::VirtualMarginToRealMargin(Margin margin)
			{
				return margin;
			}

			KeyDirection GuiDefaultAxis::RealKeyDirectionToVirtualKeyDirection(KeyDirection key)
			{
				return key;
			}

/***********************************************************************
GuiAxis
***********************************************************************/

			GuiAxis::GuiAxis(AxisDirection _axisDirection)
				:axisDirection(_axisDirection)
			{
			}

			GuiAxis::~GuiAxis()
			{
			}

			AxisDirection GuiAxis::GetDirection()
			{
				return axisDirection;
			}

			Size GuiAxis::RealSizeToVirtualSize(Size size)
			{
				switch(axisDirection)
				{
				case AxisDirection::LeftDown:
				case AxisDirection::RightDown:
				case AxisDirection::LeftUp:
				case AxisDirection::RightUp:
					return Size(size.x, size.y);
				case AxisDirection::DownLeft:
				case AxisDirection::DownRight:
				case AxisDirection::UpLeft:
				case AxisDirection::UpRight:
					return Size(size.y, size.x);
				}
				return size;
			}

			Size GuiAxis::VirtualSizeToRealSize(Size size)
			{
				return RealSizeToVirtualSize(size);
			}

			Point GuiAxis::RealPointToVirtualPoint(Size realFullSize, Point point)
			{
				Rect rect(point, Size(0, 0));
				return RealRectToVirtualRect(realFullSize, rect).LeftTop();
			}

			Point GuiAxis::VirtualPointToRealPoint(Size realFullSize, Point point)
			{
				Rect rect(point, Size(0, 0));
				return VirtualRectToRealRect(realFullSize, rect).LeftTop();
			}

			Rect GuiAxis::RealRectToVirtualRect(Size realFullSize, Rect rect)
			{
				vint x1=rect.x1;
				vint x2=realFullSize.x-rect.x2;
				vint y1=rect.y1;
				vint y2=realFullSize.y-rect.y2;
				vint w=rect.Width();
				vint h=rect.Height();
				switch(axisDirection)
				{
				case AxisDirection::LeftDown:
					return Rect(Point(x2, y1), Size(w, h));
				case AxisDirection::RightDown:
					return Rect(Point(x1, y1), Size(w, h));
				case AxisDirection::LeftUp:
					return Rect(Point(x2, y2), Size(w, h));
				case AxisDirection::RightUp:
					return Rect(Point(x1, y2), Size(w, h));
				case AxisDirection::DownLeft:
					return Rect(Point(y1, x2), Size(h, w));
				case AxisDirection::DownRight:
					return Rect(Point(y1, x1), Size(h, w));
				case AxisDirection::UpLeft:
					return Rect(Point(y2, x2), Size(h, w));
				case AxisDirection::UpRight:
					return Rect(Point(y2, x1), Size(h, w));
				}
				return rect;
			}

			Rect GuiAxis::VirtualRectToRealRect(Size realFullSize, Rect rect)
			{
				realFullSize=RealSizeToVirtualSize(realFullSize);
				vint x1=rect.x1;
				vint x2=realFullSize.x-rect.x2;
				vint y1=rect.y1;
				vint y2=realFullSize.y-rect.y2;
				vint w=rect.Width();
				vint h=rect.Height();
				switch(axisDirection)
				{
				case AxisDirection::LeftDown:
					return Rect(Point(x2, y1), Size(w, h));
				case AxisDirection::RightDown:
					return Rect(Point(x1, y1), Size(w, h));
				case AxisDirection::LeftUp:
					return Rect(Point(x2, y2), Size(w, h));
				case AxisDirection::RightUp:
					return Rect(Point(x1, y2), Size(w, h));
				case AxisDirection::DownLeft:
					return Rect(Point(y2, x1), Size(h, w));
				case AxisDirection::DownRight:
					return Rect(Point(y1, x1), Size(h, w));
				case AxisDirection::UpLeft:
					return Rect(Point(y2, x2), Size(h, w));
				case AxisDirection::UpRight:
					return Rect(Point(y1, x2), Size(h, w));
				}
				return rect;
			}

			Margin GuiAxis::RealMarginToVirtualMargin(Margin margin)
			{
				vint x1=margin.left;
				vint x2=margin.right;
				vint y1=margin.top;
				vint y2=margin.bottom;
				switch(axisDirection)
				{
				case AxisDirection::LeftDown:
					return Margin(x2, y1, x1, y2);
				case AxisDirection::RightDown:
					return Margin(x1, y1, x2, y2);
				case AxisDirection::LeftUp:
					return Margin(x2, y2, x1, y1);
				case AxisDirection::RightUp:
					return Margin(x1, y2, x2, y1);
				case AxisDirection::DownLeft:
					return Margin(y1, x2, y2, x1);
				case AxisDirection::DownRight:
					return Margin(y1, x1, y2, x2);
				case AxisDirection::UpLeft:
					return Margin(y2, x2, y1, x1);
				case AxisDirection::UpRight:
					return Margin(y2, x1, y1, x2);
				}
				return margin;
			}

			Margin GuiAxis::VirtualMarginToRealMargin(Margin margin)
			{
				vint x1=margin.left;
				vint x2=margin.right;
				vint y1=margin.top;
				vint y2=margin.bottom;
				switch(axisDirection)
				{
				case AxisDirection::LeftDown:
					return Margin(x2, y1, x1, y2);
				case AxisDirection::RightDown:
					return Margin(x1, y1, x2, y2);
				case AxisDirection::LeftUp:
					return Margin(x2, y2, x1, y1);
				case AxisDirection::RightUp:
					return Margin(x1, y2, x2, y1);
				case AxisDirection::DownLeft:
					return Margin(y2, x1, y1, x2);
				case AxisDirection::DownRight:
					return Margin(y1, x1, y2, x2);
				case AxisDirection::UpLeft:
					return Margin(y2, x2, y1, x1);
				case AxisDirection::UpRight:
					return Margin(y1, x2, y2, x1);
				default:;
				}
				return margin;
			}

			KeyDirection GuiAxis::RealKeyDirectionToVirtualKeyDirection(KeyDirection key)
			{
				bool pageKey=false;
				switch(key)
				{
				case KeyDirection::PageUp:
					pageKey=true;
					key=KeyDirection::Up;
					break;
				case KeyDirection::PageDown:
					pageKey=true;
					key=KeyDirection::Down;
					break;
				case KeyDirection::PageLeft:
					pageKey=true;
					key=KeyDirection::Left;
					break;
				case KeyDirection::PageRight:
					pageKey=true;
					key=KeyDirection::Right;
					break;
				default:;
				}

				switch(key)
				{
				case KeyDirection::Up:
					switch(axisDirection)
					{
					case AxisDirection::LeftDown:	key=KeyDirection::Up;		break;
					case AxisDirection::RightDown:	key=KeyDirection::Up;		break;
					case AxisDirection::LeftUp:		key=KeyDirection::Down;	break;
					case AxisDirection::RightUp:	key=KeyDirection::Down;	break;
					case AxisDirection::DownLeft:	key=KeyDirection::Left;	break;
					case AxisDirection::DownRight:	key=KeyDirection::Left;	break;
					case AxisDirection::UpLeft:		key=KeyDirection::Right;	break;
					case AxisDirection::UpRight:	key=KeyDirection::Right;	break;
					}
					break;
				case KeyDirection::Down:
					switch(axisDirection)
					{
					case AxisDirection::LeftDown:	key=KeyDirection::Down;	break;
					case AxisDirection::RightDown:	key=KeyDirection::Down;	break;
					case AxisDirection::LeftUp:		key=KeyDirection::Up;		break;
					case AxisDirection::RightUp:	key=KeyDirection::Up;		break;
					case AxisDirection::DownLeft:	key=KeyDirection::Right;	break;
					case AxisDirection::DownRight:	key=KeyDirection::Right;	break;
					case AxisDirection::UpLeft:		key=KeyDirection::Left;	break;
					case AxisDirection::UpRight:	key=KeyDirection::Left;	break;
					}
					break;
				case KeyDirection::Left:
					switch(axisDirection)
					{
					case AxisDirection::LeftDown:	key=KeyDirection::Right;	break;
					case AxisDirection::RightDown:	key=KeyDirection::Left;	break;
					case AxisDirection::LeftUp:		key=KeyDirection::Right;	break;
					case AxisDirection::RightUp:	key=KeyDirection::Left;	break;
					case AxisDirection::DownLeft:	key=KeyDirection::Down;	break;
					case AxisDirection::DownRight:	key=KeyDirection::Up;		break;
					case AxisDirection::UpLeft:		key=KeyDirection::Down;	break;
					case AxisDirection::UpRight:	key=KeyDirection::Up;		break;
					}
					break;
				case KeyDirection::Right:
					switch(axisDirection)
					{
					case AxisDirection::LeftDown:	key=KeyDirection::Left;	break;
					case AxisDirection::RightDown:	key=KeyDirection::Right;	break;
					case AxisDirection::LeftUp:		key=KeyDirection::Left;	break;
					case AxisDirection::RightUp:	key=KeyDirection::Right;	break;
					case AxisDirection::DownLeft:	key=KeyDirection::Up;		break;
					case AxisDirection::DownRight:	key=KeyDirection::Down;	break;
					case AxisDirection::UpLeft:		key=KeyDirection::Up;		break;
					case AxisDirection::UpRight:	key=KeyDirection::Down;	break;
					}
					break;
				case KeyDirection::Home:
					switch(axisDirection)
					{
					case AxisDirection::LeftDown:	key=KeyDirection::Home;	break;
					case AxisDirection::RightDown:	key=KeyDirection::Home;	break;
					case AxisDirection::LeftUp:		key=KeyDirection::End;	break;
					case AxisDirection::RightUp:	key=KeyDirection::End;	break;
					case AxisDirection::DownLeft:	key=KeyDirection::Home;	break;
					case AxisDirection::DownRight:	key=KeyDirection::Home;	break;
					case AxisDirection::UpLeft:		key=KeyDirection::End;	break;
					case AxisDirection::UpRight:	key=KeyDirection::End;	break;
					}
					break;
				case KeyDirection::End:
					switch(axisDirection)
					{
					case AxisDirection::LeftDown:	key=KeyDirection::End;	break;
					case AxisDirection::RightDown:	key=KeyDirection::End;	break;
					case AxisDirection::LeftUp:		key=KeyDirection::Home;	break;
					case AxisDirection::RightUp:	key=KeyDirection::Home;	break;
					case AxisDirection::DownLeft:	key=KeyDirection::End;	break;
					case AxisDirection::DownRight:	key=KeyDirection::End;	break;
					case AxisDirection::UpLeft:		key=KeyDirection::Home;	break;
					case AxisDirection::UpRight:	key=KeyDirection::Home;	break;
					}
					break;
				default:;
				}

				if(pageKey)
				{
					switch(key)
					{
					case KeyDirection::Up:
						key=KeyDirection::PageUp;
						break;
					case KeyDirection::Down:
						key=KeyDirection::PageDown;
						break;
					case KeyDirection::Left:
						key=KeyDirection::PageLeft;
						break;
					case KeyDirection::Right:
						key=KeyDirection::PageRight;
						break;
					default:;
					}
				}
				return key;
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSCOMPOSITION\GUIGRAPHICSFLOWCOMPOSITION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace collections;

/***********************************************************************
GuiFlowComposition
***********************************************************************/

			void GuiFlowComposition::Layout_UpdateFlowItemLayout(vint maxVirtualWidth)
			{
				for (auto item : layout_flowItems)
				{
					item->Layout_SetCachedMinSize(item->Layout_CalculateMinSizeHelper());
				}

				if (layout_lastVirtualWidth != maxVirtualWidth)
				{
					layout_invalid = true;
					layout_lastVirtualWidth = maxVirtualWidth;
				}

				if (!layout_invalid) return;
				layout_invalid = false;

				vint currentIndex = 0;
				vint rowTop = 0;

				while (currentIndex < layout_flowItems.Count())
				{
					auto currentItemVirtualMinSize = axis->RealSizeToVirtualSize(layout_flowItems[currentIndex]->GetCachedMinSize());
					vint rowWidth = currentItemVirtualMinSize.x;
					vint rowHeight = currentItemVirtualMinSize.y;
					vint rowItemCount = 1;

					for (vint i = currentIndex + 1; i < layout_flowItems.Count(); i++)
					{
						auto itemSize = axis->RealSizeToVirtualSize(layout_flowItems[i]->GetCachedMinSize());
						vint itemWidth = itemSize.x + columnPadding;
						if (rowWidth + itemWidth > maxVirtualWidth)
						{
							break;
						}
						rowWidth += itemWidth;
						if (rowHeight < itemSize.y)
						{
							rowHeight = itemSize.y;
						}
						rowItemCount++;
					}

					vint baseLine = 0;
					Array<vint> itemBaseLines(rowItemCount);
					for (vint i = 0; i < rowItemCount; i++)
					{
						vint index = currentIndex + i;
						vint itemBaseLine = 0;
						auto itemSize = axis->RealSizeToVirtualSize(layout_flowItems[index]->GetCachedMinSize());

						auto option = layout_flowItems[index]->GetFlowOption();
						switch (option.baseline)
						{
						case GuiFlowOption::FromTop:
							itemBaseLine = option.distance;
							break;
						case GuiFlowOption::FromBottom:
							itemBaseLine = itemSize.y - option.distance;
							break;
						case GuiFlowOption::Percentage:
							itemBaseLine = (vint)(itemSize.y*option.percentage);
							break;
						}

						itemBaseLines[i] = itemBaseLine;
						if (baseLine < itemBaseLine)
						{
							baseLine = itemBaseLine;
						}
					}

					vint rowUsedWidth = 0;
					for (vint i = 0; i < rowItemCount; i++)
					{
						vint index = currentIndex + i;
						auto itemSize = axis->RealSizeToVirtualSize(layout_flowItems[index]->GetCachedMinSize());

						vint itemLeft = 0;
						vint itemTop = rowTop + baseLine - itemBaseLines[i];

						switch (alignment)
						{
						case FlowAlignment::Left:
							itemLeft = rowUsedWidth + i * columnPadding;
							break;
						case FlowAlignment::Center:
							itemLeft = rowUsedWidth + i * columnPadding + (maxVirtualWidth - rowWidth) / 2;
							break;
						case FlowAlignment::Right:
							itemLeft = rowUsedWidth + i * columnPadding + (maxVirtualWidth - rowWidth);
							break;
						case FlowAlignment::Extend:
							if (i == 0)
							{
								itemLeft = rowUsedWidth;
							}
							else
							{
								itemLeft = rowUsedWidth + (vint)((double)(maxVirtualWidth - rowWidth) * i / (rowItemCount - 1)) + i * columnPadding;
							}
							break;
						}

						layout_flowItems[index]->layout_virtualBounds = Rect({ itemLeft,itemTop }, itemSize);
						rowUsedWidth += itemSize.x;
					}

					rowTop += rowHeight + rowPadding;
					currentIndex += rowItemCount;
				}

				layout_minVirtualHeight = rowTop == 0 ? 0 : rowTop - rowPadding;
			}

			Size GuiFlowComposition::Layout_UpdateFlowItemLayoutByConstraint(Size constraintSize)
			{
				Size extraSize(
					extraMargin.left + extraMargin.right,
					extraMargin.top + extraMargin.bottom
				);
				constraintSize.x -= extraSize.x;
				constraintSize.y -= extraSize.y;
				if (constraintSize.x < 0) constraintSize.x = 0;
				if (constraintSize.y < 0) constraintSize.y = 0;

				vint maxVirtualWidth = axis->RealSizeToVirtualSize(constraintSize).x;
				Layout_UpdateFlowItemLayout(maxVirtualWidth);
				return extraSize;
			}

			void GuiFlowComposition::OnChildInserted(GuiGraphicsComposition* child)
			{
				GuiBoundsComposition::OnChildInserted(child);
				auto item = dynamic_cast<GuiFlowItemComposition*>(child);
				if (item && !layout_flowItems.Contains(item))
				{
					layout_flowItems.Add(item);
				}
			}

			void GuiFlowComposition::OnChildRemoved(GuiGraphicsComposition* child)
			{
				GuiBoundsComposition::OnChildRemoved(child);
				auto item = dynamic_cast<GuiFlowItemComposition*>(child);
				if (item)
				{
					layout_flowItems.Remove(item);
				}
			}

			void GuiFlowComposition::OnCompositionStateChanged()
			{
				GuiBoundsComposition::OnCompositionStateChanged();
				layout_invalid = true;
			}

			Size GuiFlowComposition::Layout_CalculateMinSize()
			{
				Size minSize = GuiBoundsComposition::Layout_CalculateMinSize();

				if (GetMinSizeLimitation() == GuiGraphicsComposition::LimitToElementAndChildren && layout_flowItems.Count() > 0)
				{
					Size cachedSize = cachedBounds.GetSize();
					Size constraintSize(
						minSize.x > cachedSize.x ? minSize.x : cachedSize.x,
						minSize.y > cachedSize.y ? minSize.y : cachedSize.y
					);

					Size extraSize = Layout_UpdateFlowItemLayoutByConstraint(constraintSize);
					Size minFlowSize = axis->VirtualSizeToRealSize(Size(0, layout_minVirtualHeight));
					minFlowSize.x += extraSize.x;
					minFlowSize.y += extraSize.y;

					if (minSize.x < minFlowSize.x) minSize.x = minFlowSize.x;
					if (minSize.y < minFlowSize.y) minSize.y = minFlowSize.y;
				}

				return minSize;
			}

			Rect GuiFlowComposition::Layout_CalculateBounds(Size parentSize)
			{
				Rect bounds = GuiBoundsComposition::Layout_CalculateBounds(parentSize);
				Size extraSize = Layout_UpdateFlowItemLayoutByConstraint(bounds.GetSize());
				Size contentSize(
					bounds.Width() - extraSize.x,
					bounds.Height() - extraSize.y
				);
				for (auto item : layout_flowItems)
				{
					item->Layout_SetFlowItemBounds(contentSize, item->layout_virtualBounds);
				}
				return bounds;
			}

			const GuiFlowComposition::ItemCompositionList& GuiFlowComposition::GetFlowItems()
			{
				return layout_flowItems;
			}

			bool GuiFlowComposition::InsertFlowItem(vint index, GuiFlowItemComposition* item)
			{
				index = layout_flowItems.Insert(index, item);
				if (AddChild(item))
				{
					return true;
				}
				layout_flowItems.RemoveAt(index);
				return false;
			}


			Margin GuiFlowComposition::GetExtraMargin()
			{
				return extraMargin;
			}

			void GuiFlowComposition::SetExtraMargin(Margin value)
			{
				if (extraMargin != value)
				{
					extraMargin = value;
					InvokeOnCompositionStateChanged();
				}
			}

			vint GuiFlowComposition::GetRowPadding()
			{
				return rowPadding;
			}

			void GuiFlowComposition::SetRowPadding(vint value)
			{
				if (rowPadding != value)
				{
					rowPadding = value;
					InvokeOnCompositionStateChanged();
				}
			}

			vint GuiFlowComposition::GetColumnPadding()
			{
				return columnPadding;
			}

			void GuiFlowComposition::SetColumnPadding(vint value)
			{
				if (columnPadding != value)
				{
					columnPadding = value;
					InvokeOnCompositionStateChanged();
				}
			}

			Ptr<IGuiAxis> GuiFlowComposition::GetAxis()
			{
				return axis;
			}

			void GuiFlowComposition::SetAxis(Ptr<IGuiAxis> value)
			{
				if (value)
				{
					axis = value;
					InvokeOnCompositionStateChanged();
				}
			}

			FlowAlignment GuiFlowComposition::GetAlignment()
			{
				return alignment;
			}

			void GuiFlowComposition::SetAlignment(FlowAlignment value)
			{
				if (alignment != value)
				{
					alignment = value;
					InvokeOnCompositionStateChanged();
				}
			}

/***********************************************************************
GuiFlowItemComposition
***********************************************************************/

			void GuiFlowItemComposition::Layout_SetFlowItemBounds(Size contentSize, Rect virtualBounds)
			{
				Rect result = layout_flowParent->axis->VirtualRectToRealRect(contentSize, virtualBounds);

				result.x1 += layout_flowParent->extraMargin.left;
				result.x2 += layout_flowParent->extraMargin.left;
				result.y1 += layout_flowParent->extraMargin.top;
				result.y2 += layout_flowParent->extraMargin.top;

				result.x1 -= extraMargin.left;
				result.y1 -= extraMargin.top;
				result.x2 += extraMargin.right;
				result.y2 += extraMargin.bottom;

				Layout_SetCachedBounds(result);
			}

			void GuiFlowItemComposition::OnParentLineChanged()
			{
				layout_flowParent = dynamic_cast<GuiFlowComposition*>(GetParent());
				GuiGraphicsComposition::OnParentLineChanged();
			}

			GuiFlowItemComposition::GuiFlowItemComposition()
			{
				SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				CachedMinSizeChanged.AttachLambda([this](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
				{
					if (layout_flowParent) layout_flowParent->layout_invalid = true;
				});
			}

			Margin GuiFlowItemComposition::GetExtraMargin()
			{
				return extraMargin;
			}

			void GuiFlowItemComposition::SetExtraMargin(Margin value)
			{
				if (extraMargin != value)
				{
					extraMargin = value;
					InvokeOnCompositionStateChanged();
				}
			}

			GuiFlowOption GuiFlowItemComposition::GetFlowOption()
			{
				return option;
			}

			void GuiFlowItemComposition::SetFlowOption(GuiFlowOption value)
			{
				if (option != value)
				{
					option = value;
					if (layout_flowParent) layout_flowParent->layout_invalid = true;
					InvokeOnCompositionStateChanged();
				}
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSCOMPOSITION\GUIGRAPHICSREPEATCOMPOSITION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace reflection::description;

/***********************************************************************
GuiRepeatCompositionBase
***********************************************************************/

			GuiRepeatCompositionBase::GuiRepeatCompositionBase()
			{
			}

			GuiRepeatCompositionBase::~GuiRepeatCompositionBase()
			{
				if (itemChangedHandler)
				{
					itemSource.Cast<IValueObservableList>()->ItemChanged.Remove(itemChangedHandler);
				}
			}

			GuiRepeatCompositionBase::ItemStyleProperty GuiRepeatCompositionBase::GetItemTemplate()
			{
				return itemTemplate;
			}

			void GuiRepeatCompositionBase::SetItemTemplate(ItemStyleProperty value)
			{
				OnClearItems();
				itemTemplate = value;
				if (itemTemplate && itemSource)
				{
					OnInstallItems();
				}
			}

			Ptr<IValueEnumerable> GuiRepeatCompositionBase::GetItemSource()
			{
				return itemSource;
			}

			void GuiRepeatCompositionBase::SetItemSource(Ptr<IValueEnumerable> value)
			{
				if (value != itemSource)
				{
					if (itemChangedHandler)
					{
						itemSource.Cast<IValueObservableList>()->ItemChanged.Remove(itemChangedHandler);
						itemChangedHandler = {};
					}

					OnClearItems();
					itemSource = value.Cast<IValueList>();
					if (!itemSource && value)
					{
						itemSource = IValueList::Create(GetLazyList<Value>(value));
					}

					if (itemTemplate && itemSource)
					{
						OnInstallItems();
					}
					if (auto observable = itemSource.Cast<IValueObservableList>())
					{
						itemChangedHandler = observable->ItemChanged.Add(this, &GuiRepeatCompositionBase::OnItemChanged);
					}
				}
			}

			description::Value GuiRepeatCompositionBase::GetContext()
			{
				return itemContext;
			}

			void GuiRepeatCompositionBase::SetContext(const description::Value& value)
			{
				if (itemContext != value)
				{
					itemContext = value;
					OnUpdateContext();

					GuiEventArgs arguments(dynamic_cast<GuiGraphicsComposition*>(this));
					ContextChanged.Execute(arguments);
				}
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSCOMPOSITION\GUIGRAPHICSREPEATCOMPOSITION_NONVIRTIAL.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{

/***********************************************************************
GuiNonVirtialRepeatCompositionBase
***********************************************************************/

			void GuiNonVirtialRepeatCompositionBase::OnItemChanged(vint index, vint oldCount, vint newCount)
			{
				if (itemTemplate && itemSource)
				{
					for (vint i = oldCount - 1; i >= 0; i--)
					{
						RemoveItem(index + i);
					}

					for (vint i = 0; i < newCount; i++)
					{
						InstallItem(index + i);
					}
				}
			}

			void GuiNonVirtialRepeatCompositionBase::OnClearItems()
			{
				vint count = GetRepeatCompositionCount();
				for (vint i = count - 1; i >= 0; i--)
				{
					RemoveItem(i);
				}
			}

			void GuiNonVirtialRepeatCompositionBase::OnInstallItems()
			{
				if (itemTemplate && itemSource)
				{
					vint count = itemSource->GetCount();
					for (vint i = 0; i < count; i++)
					{
						InstallItem(i);
					}
				}
			}

			void GuiNonVirtialRepeatCompositionBase::OnUpdateContext()
			{
				vint count = GetRepeatCompositionCount();
				for (vint i = 0; i < count; i++)
				{
					auto rc = GetRepeatComposition(i);
					auto it = dynamic_cast<templates::GuiTemplate*>(rc->Children()[0]);
					it->SetContext(itemContext);
				}
			}

			void GuiNonVirtialRepeatCompositionBase::RemoveItem(vint index)
			{
				GuiItemEventArgs arguments(dynamic_cast<GuiGraphicsComposition*>(this));
				arguments.itemIndex = index;
				ItemRemoved.Execute(arguments);

				auto item = RemoveRepeatComposition(index);
				SafeDeleteComposition(item);
			}

			void GuiNonVirtialRepeatCompositionBase::InstallItem(vint index)
			{
				auto source = itemSource->Get(index);
				auto templateItem = itemTemplate(source);
				auto item = InsertRepeatComposition(index);

				templateItem->SetAlignmentToParent(Margin(0, 0, 0, 0));
				templateItem->SetContext(itemContext);
				item->SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				item->AddChild(templateItem);

				GuiItemEventArgs arguments(dynamic_cast<GuiGraphicsComposition*>(this));
				arguments.itemIndex = index;
				ItemInserted.Execute(arguments);
			}

			GuiNonVirtialRepeatCompositionBase::GuiNonVirtialRepeatCompositionBase()
			{
			}

			GuiNonVirtialRepeatCompositionBase::~GuiNonVirtialRepeatCompositionBase()
			{
			}

/***********************************************************************
GuiRepeatStackComposition
***********************************************************************/

			vint GuiRepeatStackComposition::GetRepeatCompositionCount()
			{
				return GetStackItems().Count();
			}

			GuiGraphicsComposition* GuiRepeatStackComposition::GetRepeatComposition(vint index)
			{
				return GetStackItems()[index];
			}

			GuiGraphicsComposition* GuiRepeatStackComposition::InsertRepeatComposition(vint index)
			{
				CHECK_ERROR(0 <= index && index <= GetStackItems().Count(), L"GuiRepeatStackComposition::InsertRepeatComposition(vint)#Index out of range.");
				auto item = new GuiStackItemComposition;
				InsertStackItem(index, item);
				return item;
			}

			GuiGraphicsComposition* GuiRepeatStackComposition::RemoveRepeatComposition(vint index)
			{
				auto item = GetStackItems()[index];
				RemoveChild(item);
				return item;
			}

			GuiRepeatStackComposition::GuiRepeatStackComposition()
			{
				ItemInserted.SetAssociatedComposition(this);
				ItemRemoved.SetAssociatedComposition(this);
				ContextChanged.SetAssociatedComposition(this);
			}

			GuiRepeatStackComposition::~GuiRepeatStackComposition()
			{
			}

/***********************************************************************
GuiRepeatFlowComposition
***********************************************************************/

			vint GuiRepeatFlowComposition::GetRepeatCompositionCount()
			{
				return GetFlowItems().Count();
			}

			GuiGraphicsComposition* GuiRepeatFlowComposition::GetRepeatComposition(vint index)
			{
				return GetFlowItems()[index];
			}

			GuiGraphicsComposition* GuiRepeatFlowComposition::InsertRepeatComposition(vint index)
			{
				CHECK_ERROR(0 <= index && index <= GetFlowItems().Count(), L"GuiRepeatStackComposition::InsertRepeatComposition(vint)#Index out of range.");
				auto item = new GuiFlowItemComposition;
				InsertFlowItem(index, item);
				return item;
			}

			GuiGraphicsComposition* GuiRepeatFlowComposition::RemoveRepeatComposition(vint index)
			{
				auto item = GetFlowItems()[index];
				RemoveChild(item);
				return item;
			}

			GuiRepeatFlowComposition::GuiRepeatFlowComposition()
			{
				ItemInserted.SetAssociatedComposition(this);
				ItemRemoved.SetAssociatedComposition(this);
				ContextChanged.SetAssociatedComposition(this);
			}

			GuiRepeatFlowComposition::~GuiRepeatFlowComposition()
			{
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSCOMPOSITION\GUIGRAPHICSREPEATCOMPOSITION_VIRTUAL.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace collections;

/***********************************************************************
GuiVirtualRepeatCompositionBase
***********************************************************************/

			void GuiVirtualRepeatCompositionBase::Layout_UpdateIndex(ItemStyleRecord style, vint index)
			{
			}

			void GuiVirtualRepeatCompositionBase::Layout_UpdateViewBounds(Rect value, bool forceUpdateTotalSize)
			{
				auto old = GetViewLocation();
				Rect oldBounds = viewBounds;
				viewBounds = value;
				OnViewChangedInternal(oldBounds, value, forceUpdateTotalSize);
				if (old != GetViewLocation())
				{
					ViewLocationChanged.Execute(GuiEventArgs(this));
				}
			}

			void GuiVirtualRepeatCompositionBase::Layout_UpdateViewLocation(Point value)
			{
				Layout_UpdateViewBounds(Rect(value, viewBounds.GetSize()), false);
			}

			Rect GuiVirtualRepeatCompositionBase::Layout_CalculateBounds(Size parentSize)
			{
				auto bounds = GuiBoundsComposition::Layout_CalculateBounds(parentSize);
				auto size = axis->RealSizeToVirtualSize(bounds.GetSize());
				if (size != viewBounds.GetSize() || itemSourceUpdated)
				{
					itemSourceUpdated = false;
					Layout_UpdateViewBounds(Rect(viewBounds.LeftTop(), size), true);
				}
				return bounds;
			}

			void GuiVirtualRepeatCompositionBase::Layout_ResetLayout()
			{
				viewBounds = Rect({ 0,0 }, { 0,0 });
				ViewLocationChanged.Execute(GuiEventArgs(this));
				OnResetViewLocation();
				itemSourceUpdated = true;
				Layout_InvalidateItemSizeCache();
				AdoptedSizeInvalidated.Execute(GuiEventArgs(this));
			}

			void GuiVirtualRepeatCompositionBase::Layout_SetStyleAlignmentToParent(ItemStyleRecord style, Margin value)
			{
				style->SetAlignmentToParent(axis->VirtualMarginToRealMargin(value));
			}

			Size GuiVirtualRepeatCompositionBase::Layout_GetStylePreferredSize(ItemStyleRecord style)
			{
				return axis->RealSizeToVirtualSize(style->GetCachedMinSize());
			}

			Rect GuiVirtualRepeatCompositionBase::Layout_GetStyleBounds(ItemStyleRecord style)
			{
				return axis->RealRectToVirtualRect(axis->VirtualSizeToRealSize(viewBounds.GetSize()), style->GetCachedBounds());
			}

			void GuiVirtualRepeatCompositionBase::Layout_SetStyleBounds(ItemStyleRecord style, Rect value)
			{
				return style->SetExpectedBounds(axis->VirtualRectToRealRect(axis->VirtualSizeToRealSize(viewBounds.GetSize()), value));
			}

			void GuiVirtualRepeatCompositionBase::OnStyleCachedMinSizeChanged(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
			{
				InvalidateLayout();
			}

			void GuiVirtualRepeatCompositionBase::AttachEventHandler(GuiGraphicsComposition* itemStyle)
			{
				eventHandlers.Add(itemStyle, itemStyle->CachedMinSizeChanged.AttachMethod(this, &GuiVirtualRepeatCompositionBase::OnStyleCachedMinSizeChanged));
			}

			void GuiVirtualRepeatCompositionBase::DetachEventHandler(GuiGraphicsComposition* itemStyle)
			{
				vint index = eventHandlers.Keys().IndexOf(itemStyle);
				if (index != -1)
				{
					auto eventHandler = eventHandlers.Values()[index];
					itemStyle->CachedBoundsChanged.Detach(eventHandler);
					eventHandlers.Remove(itemStyle);
				}
			}

			void GuiVirtualRepeatCompositionBase::OnChildRemoved(GuiGraphicsComposition* child)
			{
				DetachEventHandler(child);
				GuiBoundsComposition::OnChildRemoved(child);
			}

			void GuiVirtualRepeatCompositionBase::OnItemChanged(vint start, vint oldCount, vint newCount)
			{
				itemSourceUpdated = true;
				InvokeOnCompositionStateChanged();

				vint visibleCount = visibleStyles.Count();
				vint itemCount = itemSource->GetCount();
				SortedList<ItemStyleRecord> reusedStyles;
				for (vint i = 0; i < visibleCount; i++)
				{
					vint index = startIndex + i;
					if (index >= itemCount)
					{
						break;
					}

					vint oldIndex = -1;
					if (index < start)
					{
						oldIndex = index;
					}
					else if (index >= start + newCount)
					{
						oldIndex = index - newCount + oldCount;
					}

					if (oldIndex != -1)
					{
						if (oldIndex >= startIndex && oldIndex < startIndex + visibleCount)
						{
							auto style = visibleStyles[oldIndex - startIndex];
							reusedStyles.Add(style);
							visibleStyles.Add(style);
						}
						else
						{
							oldIndex = -1;
						}
					}
					if (oldIndex == -1)
					{
						visibleStyles.Add(CreateStyle(index));
					}
				}

				for (vint i = 0; i < visibleCount; i++)
				{
					auto style = visibleStyles[i];
					if (!reusedStyles.Contains(style))
					{
						DeleteStyle(style);
					}
				}

				visibleStyles.RemoveRange(0, visibleCount);
				for (auto [style, i] : indexed(visibleStyles))
				{
					Layout_UpdateIndex(style, startIndex + i);
				}
			}

			void GuiVirtualRepeatCompositionBase::OnClearItems()
			{
				startIndex = 0;
				for (auto style : visibleStyles)
				{
					DeleteStyle(style);
				}
				visibleStyles.Clear();
				Layout_ResetLayout();
			}

			void GuiVirtualRepeatCompositionBase::OnInstallItems()
			{
				// nothing needs to be done here
				// visibleStyles will be recreated in the next round of layout
			}

			void GuiVirtualRepeatCompositionBase::OnUpdateContext()
			{
				for (auto style : visibleStyles)
				{
					style->SetContext(itemContext);
				}
			}

			void GuiVirtualRepeatCompositionBase::OnResetViewLocation()
			{
			}

			GuiVirtualRepeatCompositionBase::ItemStyleRecord GuiVirtualRepeatCompositionBase::CreateStyleInternal(vint index)
			{
				auto source = itemSource->Get(index);
				auto itemStyle = itemTemplate(source);
				itemStyle->SetContext(itemContext);
				return itemStyle;
			}

			void GuiVirtualRepeatCompositionBase::DeleteStyleInternal(ItemStyleRecord style)
			{
				SafeDeleteComposition(style);
			}

			vint GuiVirtualRepeatCompositionBase::CalculateAdoptedSize(vint expectedSize, vint count, vint itemSize)
			{
				vint visibleCount = expectedSize / itemSize;
				if (count < visibleCount)
				{
					visibleCount = count;
				}
				else if (count > visibleCount)
				{
					vint deltaA = expectedSize - visibleCount * itemSize;
					vint deltaB = itemSize - deltaA;
					if (deltaB < deltaA)
					{
						visibleCount++;
					}
				}
				return visibleCount * itemSize;
			}

			GuiVirtualRepeatCompositionBase::ItemStyleRecord GuiVirtualRepeatCompositionBase::CreateStyle(vint index)
			{
				auto itemStyle = CreateStyleInternal(index);
				AddChild(itemStyle);
				itemStyle->ForceCalculateSizeImmediately();
				AttachEventHandler(itemStyle);
				return itemStyle;
			}

			void GuiVirtualRepeatCompositionBase::DeleteStyle(ItemStyleRecord style)
			{
				DetachEventHandler(style);
				DeleteStyleInternal(style);
			}

			void GuiVirtualRepeatCompositionBase::UpdateFullSize()
			{
				Size fullSize, minimumSize;
				Layout_CalculateTotalSize(fullSize, minimumSize);
				realFullSize = axis->VirtualSizeToRealSize(fullSize);
				realMinimumFullSize = axis->VirtualSizeToRealSize(minimumSize);
			}

			void GuiVirtualRepeatCompositionBase::OnViewChangedInternal(Rect oldBounds, Rect newBounds, bool forceUpdateTotalSize)
			{
				bool needToUpdateTotalSize = forceUpdateTotalSize;

				if (itemTemplate && itemSource)
				{
					while (true)
					{
						bool needRestart = false;

						vint endIndex = startIndex + visibleStyles.Count() - 1;
						vint newStartIndex = 0;
						vint itemCount = itemSource->GetCount();
						Layout_BeginPlaceItem(true, newBounds, newStartIndex);
						if (newStartIndex < 0) newStartIndex = 0;

						StyleList newVisibleStyles;
						for (vint i = newStartIndex; i < itemCount; i++)
						{
							bool reuseOldStyle = startIndex <= i && i <= endIndex;
							auto style = reuseOldStyle ? visibleStyles[i - startIndex] : CreateStyle(i);
							newVisibleStyles.Add(style);

							Rect bounds;
							Margin alignmentToParent;
							auto placeItemResult = Layout_PlaceItem(true, !reuseOldStyle, i, style, newBounds, bounds, alignmentToParent);

							if (placeItemResult != VirtualRepeatPlaceItemResult::None)
							{
								needRestart = placeItemResult == VirtualRepeatPlaceItemResult::Restart;
								break;
							}
						}

						vint newEndIndex = newStartIndex + newVisibleStyles.Count() - 1;
						for (auto [style, i] : indexed(visibleStyles))
						{
							vint index = startIndex + i;
							if (index < newStartIndex || index > newEndIndex)
							{
								DeleteStyle(visibleStyles[i]);
							}
						}
						CopyFrom(visibleStyles, newVisibleStyles);

						needToUpdateTotalSize = (Layout_EndPlaceItem(true, newBounds, newStartIndex) == VirtualRepeatEndPlaceItemResult::TotalSizeUpdated) || needToUpdateTotalSize;
						startIndex = newStartIndex;

						if (!needRestart) break;
					}

					{
						vint newStartIndex = startIndex;
						Layout_BeginPlaceItem(false, viewBounds, newStartIndex);

						for (auto [style, i] : indexed(visibleStyles))
						{
							Rect bounds;
							Margin alignmentToParent(-1, -1, -1, -1);
							Layout_PlaceItem(false, false, startIndex + i, style, viewBounds, bounds, alignmentToParent);

							bounds.x1 -= viewBounds.x1;
							bounds.x2 -= viewBounds.x1;
							bounds.y1 -= viewBounds.y1;
							bounds.y2 -= viewBounds.y1;

							Layout_SetStyleAlignmentToParent(style, alignmentToParent);
							Layout_SetStyleBounds(style, bounds);
						}

						needToUpdateTotalSize = (Layout_EndPlaceItem(false, viewBounds, startIndex) == VirtualRepeatEndPlaceItemResult::TotalSizeUpdated) || needToUpdateTotalSize;
					}
				}
				else if (realFullSize != Size(0, 0))
				{
					needToUpdateTotalSize = true;
				}

				if (needToUpdateTotalSize)
				{
					UpdateFullSize();
					TotalSizeChanged.Execute(GuiEventArgs(this));
					AdoptedSizeInvalidated.Execute(GuiEventArgs(this));
				}
				Layout_EndLayout(needToUpdateTotalSize);
			}

			GuiVirtualRepeatCompositionBase::GuiVirtualRepeatCompositionBase()
			{
				AxisChanged.SetAssociatedComposition(this);
				TotalSizeChanged.SetAssociatedComposition(this);
				ViewLocationChanged.SetAssociatedComposition(this);
				AdoptedSizeInvalidated.SetAssociatedComposition(this);
			}

			GuiVirtualRepeatCompositionBase::~GuiVirtualRepeatCompositionBase()
			{
				for (auto [style, eventHandler] : eventHandlers)
				{
					style->CachedMinSizeChanged.Detach(eventHandler);
				}
				eventHandlers.Clear();
			}

			Ptr<IGuiAxis> GuiVirtualRepeatCompositionBase::GetAxis()
			{
				return axis;
			}

			void GuiVirtualRepeatCompositionBase::SetAxis(Ptr<IGuiAxis> value)
			{
				if (axis != value)
				{
					OnClearItems();
					if (!value) value = Ptr(new GuiDefaultAxis);
					axis = value;
					if (itemTemplate && itemSource)
					{
						OnInstallItems();
					}
					AxisChanged.Execute(GuiEventArgs(this));
				}
			}

			Size GuiVirtualRepeatCompositionBase::GetTotalSize()
			{
				return useMinimumFullSize ? realMinimumFullSize : realFullSize;
			}

			bool GuiVirtualRepeatCompositionBase::GetUseMinimumTotalSize()
			{
				return useMinimumFullSize;
			}

			void GuiVirtualRepeatCompositionBase::SetUseMinimumTotalSize(bool value)
			{
				if (useMinimumFullSize != value)
				{
					useMinimumFullSize = value;
					UpdateFullSize();
					TotalSizeChanged.Execute(GuiEventArgs(this));
				}
			}

			Point GuiVirtualRepeatCompositionBase::GetViewLocation()
			{
				return axis->VirtualRectToRealRect(realFullSize, viewBounds).LeftTop();
			}

			void GuiVirtualRepeatCompositionBase::SetViewLocation(Point value)
			{
				Size realSize = axis->VirtualSizeToRealSize(viewBounds.GetSize());
				Rect realBounds = Rect(value, realSize);
				Layout_UpdateViewBounds(axis->RealRectToVirtualRect(realFullSize, realBounds), false);
				OnResetViewLocation();
			}

			GuiVirtualRepeatCompositionBase::ItemStyleRecord GuiVirtualRepeatCompositionBase::GetVisibleStyle(vint itemIndex)
			{
				if (startIndex <= itemIndex && itemIndex < startIndex + visibleStyles.Count())
				{
					return visibleStyles[itemIndex - startIndex];
				}
				else
				{
					return nullptr;
				}
			}

			vint GuiVirtualRepeatCompositionBase::GetVisibleIndex(ItemStyleRecord style)
			{
				for (auto [s, i] : indexed(visibleStyles))
				{
					if (s == style)
					{
						return i + startIndex;
					}
				}
				return -1;
			}

			void GuiVirtualRepeatCompositionBase::ResetLayout(bool recreateVisibleStyles)
			{
				if (recreateVisibleStyles)
				{
					OnClearItems();
				}
				else
				{
					Layout_ResetLayout();
				}
			}

			void GuiVirtualRepeatCompositionBase::InvalidateLayout()
			{
				itemSourceUpdated = true;
			}

			Size GuiVirtualRepeatCompositionBase::GetAdoptedSize(Size expectedSize)
			{
				Size expectedViewSize = axis->RealSizeToVirtualSize(expectedSize);
				Size adoptedViewSize = Layout_GetAdoptedSize(expectedViewSize);
				Size adoptedSize = axis->VirtualSizeToRealSize(adoptedViewSize);
				return adoptedSize;
			}

			vint GuiVirtualRepeatCompositionBase::FindItemByRealKeyDirection(vint itemIndex, compositions::KeyDirection key)
			{
				return FindItemByVirtualKeyDirection(itemIndex, axis->RealKeyDirectionToVirtualKeyDirection(key));
			}

/***********************************************************************
GuiRepeatFreeHeightItemComposition
***********************************************************************/

			void GuiRepeatFreeHeightItemComposition::EnsureOffsetForItem(vint itemIndex)
			{
				if (heights.Count() == 0) return;

				if (availableOffsetCount == 0)
				{
					availableOffsetCount = 1;
					offsets[0] = 0;
				}

				for (vint i = availableOffsetCount; i < itemIndex && i < heights.Count(); i++)
				{
					offsets[i] = offsets[i - 1] + heights[i - 1];
				}
			}

			void GuiRepeatFreeHeightItemComposition::Layout_BeginPlaceItem(bool firstPhase, Rect newBounds, vint& newStartIndex)
			{
				pi_heightUpdated = false;
				EnsureOffsetForItem(heights.Count() - 1);
				if (firstPhase)
				{
					// TODO: (enumerable) foreach:indexed
					for (vint i = 0; i < heights.Count(); i++)
					{
						if (heights[i] == 1 && startIndex <= i && i < startIndex + visibleStyles.Count() && visibleStyles[i - startIndex])
						{
							vint h = visibleStyles[i - startIndex]->GetCachedMinSize().y;
							if (h > 1)
							{
								heights[i] = h;
							}
						}
						if (offsets[i] + heights[i] > newBounds.Top())
						{
							newStartIndex = i;
							break;
						}
					}
				}
			}

			VirtualRepeatPlaceItemResult GuiRepeatFreeHeightItemComposition::Layout_PlaceItem(bool firstPhase, bool newCreatedStyle, vint index, ItemStyleRecord style, Rect viewBounds, Rect& bounds, Margin& alignmentToParent)
			{
				vint styleHeight = heights[index];
				{
					vint newStyleHeight = Layout_GetStylePreferredSize(style).y;
					if (!newCreatedStyle || styleHeight < newStyleHeight)
					{
						styleHeight = newStyleHeight;
					}
				}

				if (heights[index] != styleHeight)
				{
					heights[index] = styleHeight;
					pi_heightUpdated = true;
				}

				vint styleOffset = index == 0 ? 0 : offsets[index - 1] + heights[index - 1];
				if (availableOffsetCount <= index || offsets[index] != styleOffset)
				{
					offsets[index] = styleOffset;
					availableOffsetCount = index;
				}

				bounds = Rect(Point(0, offsets[index]), Size(viewBounds.Width(), heights[index]));

				if (bounds.Bottom() >= viewBounds.Bottom())
				{
					return VirtualRepeatPlaceItemResult::HitLastItem;
				}
				else
				{
					return VirtualRepeatPlaceItemResult::None;
				}
			}

			VirtualRepeatEndPlaceItemResult GuiRepeatFreeHeightItemComposition::Layout_EndPlaceItem(bool firstPhase, Rect newBounds, vint newStartIndex)
			{
				return pi_heightUpdated ? VirtualRepeatEndPlaceItemResult::TotalSizeUpdated : VirtualRepeatEndPlaceItemResult::None;
			}

			void GuiRepeatFreeHeightItemComposition::Layout_EndLayout(bool totalSizeUpdated)
			{
			}

			void GuiRepeatFreeHeightItemComposition::Layout_InvalidateItemSizeCache()
			{
				availableOffsetCount = 0;
				for (vint i = 0; i < heights.Count(); i++)
				{
					heights[i] = 1;
				}
			}

			void GuiRepeatFreeHeightItemComposition::Layout_CalculateTotalSize(Size& full, Size& minimum)
			{
				if (heights.Count() == 0)
				{
					full = minimum = Size(0, 0);
					return;
				}

				EnsureOffsetForItem(heights.Count());
				vint w = viewBounds.Width();
				vint h = offsets[heights.Count() - 1] + heights[heights.Count() - 1];
				full = Size(w, h);
				minimum = Size(0, h);
			}

			Size GuiRepeatFreeHeightItemComposition::Layout_GetAdoptedSize(Size expectedSize)
			{
				vint h = expectedSize.x * 2;
				if (expectedSize.y < h) expectedSize.y = h;
				return expectedSize;
			}

			void GuiRepeatFreeHeightItemComposition::OnItemChanged(vint start, vint oldCount, vint newCount)
			{
				availableOffsetCount = start;
				vint itemCount = heights.Count() + newCount - oldCount;

				if (oldCount < newCount)
				{
					heights.Resize(itemCount);
					if (start + newCount < itemCount)
					{
						memmove(&heights[start + newCount], &heights[start + oldCount], sizeof(vint) * (itemCount - start - newCount));
					}
				}
				else if (oldCount > newCount)
				{
					if (start + newCount < itemCount)
					{
						memmove(&heights[start + newCount], &heights[start + oldCount], sizeof(vint) * (itemCount - start - newCount));
					}
					heights.Resize(itemCount);
				}

				for (vint i = 0; i < newCount; i++)
				{
					heights[start + i] = 1;
				}
				offsets.Resize(itemCount);

				GuiVirtualRepeatCompositionBase::OnItemChanged(start, oldCount, newCount);
			}

			void GuiRepeatFreeHeightItemComposition::OnInstallItems()
			{
				heights.Resize(itemSource->GetCount());
				Layout_InvalidateItemSizeCache();

				offsets.Resize(itemSource->GetCount());
				EnsureOffsetForItem(heights.Count() - 1);

				GuiVirtualRepeatCompositionBase::OnInstallItems();
			}

			vint GuiRepeatFreeHeightItemComposition::FindItemByVirtualKeyDirection(vint itemIndex, compositions::KeyDirection key)
			{
				if (!itemSource) return -1;
				vint count = itemSource->GetCount();
				if (itemIndex < 0 || itemIndex >= count) return -1;

				switch (key)
				{
				case KeyDirection::Up:
					itemIndex--;
					break;
				case KeyDirection::Down:
					itemIndex++;
					break;
				case KeyDirection::Home:
					itemIndex = 0;
					break;
				case KeyDirection::End:
					itemIndex = count - 1;
					break;
				case KeyDirection::PageUp:
					itemIndex -= visibleStyles.Count();
					break;
				case KeyDirection::PageDown:
					itemIndex += visibleStyles.Count();
					break;
				default:
					return -1;
				}

				if (itemIndex < 0) return 0;
				else if (itemIndex >= count) return count - 1;
				else return itemIndex;
			}

			VirtualRepeatEnsureItemVisibleResult GuiRepeatFreeHeightItemComposition::EnsureItemVisible(vint itemIndex)
			{
				if (!itemSource) return VirtualRepeatEnsureItemVisibleResult::NotMoved;
				bool moved = false;
				while (true)
				{
					if (itemIndex < 0 || itemIndex >= itemSource->GetCount())
					{
						return VirtualRepeatEnsureItemVisibleResult::ItemNotExists;
					}

					EnsureOffsetForItem(itemIndex);
					vint offset = viewBounds.y1;
					vint top = offsets[itemIndex];
					vint bottom = top + heights[itemIndex];
					vint height = viewBounds.Height();

					Point location = viewBounds.LeftTop();

					if (offset >= top && offset + height <= bottom)
					{
						break;
					}
					else if (offset > top)
					{
						location.y = top;
					}
					else if (offset < bottom - height)
					{
						location.y = bottom - height;
					}
					else
					{
						break;
					}

					auto oldLeftTop = viewBounds.LeftTop();
					Layout_UpdateViewLocation(location);
					moved |= viewBounds.LeftTop() != oldLeftTop;
					if (viewBounds.LeftTop() != location) break;
				}
				return moved ? VirtualRepeatEnsureItemVisibleResult::Moved : VirtualRepeatEnsureItemVisibleResult::NotMoved;
			}

/***********************************************************************
GuiRepeatFixedHeightItemComposition
***********************************************************************/

			void GuiRepeatFixedHeightItemComposition::Layout_BeginPlaceItem(bool firstPhase, Rect newBounds, vint& newStartIndex)
			{
				pi_width = itemWidth;
				pi_yoffset = itemYOffset;
				if (firstPhase)
				{
					pi_rowHeight = rowHeight;
					newStartIndex = newBounds.Top() / pi_rowHeight;
				}
			}

			VirtualRepeatPlaceItemResult GuiRepeatFixedHeightItemComposition::Layout_PlaceItem(bool firstPhase, bool newCreatedStyle, vint index, ItemStyleRecord style, Rect viewBounds, Rect& bounds, Margin& alignmentToParent)
			{
				if (firstPhase)
				{
					vint styleHeight = Layout_GetStylePreferredSize(style).y;
					if (pi_rowHeight < styleHeight)
					{
						pi_rowHeight = styleHeight;
					}
				}

				vint top = pi_yoffset + index * pi_rowHeight;
				if (pi_width == -1)
				{
					alignmentToParent = Margin(0, -1, 0, -1);
					bounds = Rect(Point(0, top), Size(0, pi_rowHeight));
				}
				else
				{
					alignmentToParent = Margin(-1, -1, -1, -1);
					bounds = Rect(Point(0, top), Size(pi_width, pi_rowHeight));
				}

				if (bounds.Bottom() >= viewBounds.Bottom())
				{
					return VirtualRepeatPlaceItemResult::HitLastItem;
				}
				else
				{
					return VirtualRepeatPlaceItemResult::None;
				}
			}

			VirtualRepeatEndPlaceItemResult GuiRepeatFixedHeightItemComposition::Layout_EndPlaceItem(bool firstPhase, Rect newBounds, vint newStartIndex)
			{
				if (firstPhase)
				{
					if (pi_rowHeight != rowHeight)
					{
						rowHeight = pi_rowHeight;
						return VirtualRepeatEndPlaceItemResult::TotalSizeUpdated;
					}
				}
				return VirtualRepeatEndPlaceItemResult::None;
			}

			void GuiRepeatFixedHeightItemComposition::Layout_EndLayout(bool totalSizeUpdated)
			{
			}

			void GuiRepeatFixedHeightItemComposition::Layout_InvalidateItemSizeCache()
			{
				rowHeight = 1;
			}

			void GuiRepeatFixedHeightItemComposition::Layout_CalculateTotalSize(Size& full, Size& minimum)
			{
				if (!itemSource || itemSource->GetCount() == 0)
				{
					full = minimum = Size(0, 0);
					return;
				}

				vint w = itemWidth;
				vint w1 = w == -1 ? viewBounds.Width() : w;
				vint w2 = w == -1 ? 0 : w;
				vint h = rowHeight * itemSource->GetCount() + itemYOffset;
				full = Size(w1, h);
				minimum = Size(w2, h);
			}

			Size GuiRepeatFixedHeightItemComposition::Layout_GetAdoptedSize(Size expectedSize)
			{
				if (!itemSource) return expectedSize;
				vint y = expectedSize.y - itemYOffset;
				vint itemCount = itemSource->GetCount();
				return Size(expectedSize.x, itemYOffset + CalculateAdoptedSize(y, itemCount, rowHeight));
			}

			vint GuiRepeatFixedHeightItemComposition::FindItemByVirtualKeyDirection(vint itemIndex, compositions::KeyDirection key)
			{
				vint count = itemSource->GetCount();
				if (itemIndex < 0 || itemIndex >= count) return -1;
				vint groupCount = viewBounds.Height() / rowHeight;
				if (groupCount == 0) groupCount = 1;

				switch (key)
				{
				case KeyDirection::Up:
					itemIndex--;
					break;
				case KeyDirection::Down:
					itemIndex++;
					break;
				case KeyDirection::Home:
					itemIndex = 0;
					break;
				case KeyDirection::End:
					itemIndex = count;
					break;
				case KeyDirection::PageUp:
					itemIndex -= groupCount;
					break;
				case KeyDirection::PageDown:
					itemIndex += groupCount;
					break;
				default:
					return -1;
				}

				if (itemIndex < 0) return 0;
				else if (itemIndex >= count) return count - 1;
				else return itemIndex;
			}

			VirtualRepeatEnsureItemVisibleResult GuiRepeatFixedHeightItemComposition::EnsureItemVisible(vint itemIndex)
			{
				if (!itemSource) return VirtualRepeatEnsureItemVisibleResult::NotMoved;
				if (itemIndex < 0 || itemIndex >= itemSource->GetCount())
				{
					return VirtualRepeatEnsureItemVisibleResult::ItemNotExists;
				}

				vint viewY1 = viewBounds.y1 + itemYOffset;
				vint viewY2 = viewBounds.y2;
				vint itemY1 = itemIndex * rowHeight + itemYOffset;
				vint itemY2 = itemY1 + rowHeight;

				if (viewY2 - viewY1 < rowHeight)
				{
					if (itemY1 < viewY2 && itemY2 > viewY1)
					{
						return VirtualRepeatEnsureItemVisibleResult::NotMoved;
					}
				}
				else
				{
					if (itemY1 >= viewY1 && itemY2 <= viewY2)
					{
						return VirtualRepeatEnsureItemVisibleResult::NotMoved;
					}

					if (itemY1 < viewY1 && itemY2 > viewY1)
					{
						Layout_UpdateViewLocation({ viewBounds.x1,viewBounds.y1 + itemY1 - viewY1 });
						return VirtualRepeatEnsureItemVisibleResult::Moved;
					}

					if (itemY1 < viewY2 && itemY2 > viewY2)
					{
						Layout_UpdateViewLocation({ viewBounds.x1,viewBounds.y1 + itemY2 - viewY2 });
						return VirtualRepeatEnsureItemVisibleResult::Moved;
					}
				}

				bool up = itemY1 < viewY1;
				while (true)
				{
					if (up)
					{
						if (itemY1 >= viewY1) break;
						Layout_UpdateViewLocation({ viewBounds.x1,viewBounds.y1 + itemY1 - viewY1 });
					}
					else
					{
						if (itemY2 <= viewY2) break;
						Layout_UpdateViewLocation({ viewBounds.x1,viewBounds.y1 + itemY2 - viewY2 });
					}

					viewY1 = viewBounds.y1 + itemYOffset;
					viewY2 = viewBounds.y2;
					itemY1 = itemIndex * rowHeight + itemYOffset;
					itemY2 = itemY1 + rowHeight;
				}

				return VirtualRepeatEnsureItemVisibleResult::Moved;
			}

			vint GuiRepeatFixedHeightItemComposition::GetItemWidth()
			{
				return itemWidth;
			}

			void GuiRepeatFixedHeightItemComposition::SetItemWidth(vint value)
			{
				if (value < -1) value = -1;
				if (itemWidth != value)
				{
					itemWidth = value;
					InvalidateLayout();
				}
			}

			vint GuiRepeatFixedHeightItemComposition::GetItemYOffset()
			{
				return itemYOffset;
			}

			void GuiRepeatFixedHeightItemComposition::SetItemYOffset(vint value)
			{
				if (value < 0) value = 0;
				if (itemYOffset != value)
				{
					itemYOffset = value;
					InvalidateLayout();
				}
			}

/***********************************************************************
GuiRepeatFixedSizeMultiColumnItemComposition
***********************************************************************/

			void GuiRepeatFixedSizeMultiColumnItemComposition::Layout_BeginPlaceItem(bool firstPhase, Rect newBounds, vint& newStartIndex)
			{
				if (firstPhase)
				{
					pi_itemSize = itemSize;
					vint rows = newBounds.Top() / pi_itemSize.y;
					if (rows < 0) rows = 0;
					vint cols = newBounds.Width() / pi_itemSize.x;
					if (cols < 1) cols = 1;
					newStartIndex = rows * cols;
				}
			}

			VirtualRepeatPlaceItemResult GuiRepeatFixedSizeMultiColumnItemComposition::Layout_PlaceItem(bool firstPhase, bool newCreatedStyle, vint index, ItemStyleRecord style, Rect viewBounds, Rect& bounds, Margin& alignmentToParent)
			{
				if (firstPhase)
				{
					Size styleSize = Layout_GetStylePreferredSize(style);
					if (pi_itemSize.x < styleSize.x) pi_itemSize.x = styleSize.x;
					if (pi_itemSize.y < styleSize.y) pi_itemSize.y = styleSize.y;
				}

				vint rowItems = viewBounds.Width() / pi_itemSize.x;
				if (rowItems < 1) rowItems = 1;

				vint row = index / rowItems;
				vint col = index % rowItems;
				bounds = Rect(Point(col * pi_itemSize.x, row * pi_itemSize.y), pi_itemSize);

				if (col == rowItems - 1 && bounds.Bottom() >= viewBounds.Bottom())
				{
					return VirtualRepeatPlaceItemResult::HitLastItem;
				}
				else
				{
					return VirtualRepeatPlaceItemResult::None;
				}
			}

			VirtualRepeatEndPlaceItemResult GuiRepeatFixedSizeMultiColumnItemComposition::Layout_EndPlaceItem(bool firstPhase, Rect newBounds, vint newStartIndex)
			{
				if (firstPhase)
				{
					if (pi_itemSize != itemSize)
					{
						itemSize = pi_itemSize;
						return VirtualRepeatEndPlaceItemResult::TotalSizeUpdated;
					}
				}
				return VirtualRepeatEndPlaceItemResult::None;
			}

			void GuiRepeatFixedSizeMultiColumnItemComposition::Layout_EndLayout(bool totalSizeUpdated)
			{
			}

			void GuiRepeatFixedSizeMultiColumnItemComposition::Layout_InvalidateItemSizeCache()
			{
				itemSize = Size(1, 1);
			}

			void GuiRepeatFixedSizeMultiColumnItemComposition::Layout_CalculateTotalSize(Size& full, Size& minimum)
			{
				if (!itemSource || itemSource->GetCount() == 0)
				{
					full = minimum = Size(0, 0);
					return;
				}

				vint rowItems = viewBounds.Width() / itemSize.x;
				if (rowItems < 1) rowItems = 1;
				vint rows = itemSource->GetCount() / rowItems;
				if (itemSource->GetCount() % rowItems) rows++;

				vint h = itemSize.y * rows;
				full = Size(itemSize.x * rowItems, h);
				minimum = Size(itemSize.x, h);
			}

			Size GuiRepeatFixedSizeMultiColumnItemComposition::Layout_GetAdoptedSize(Size expectedSize)
			{
				if (!itemSource) return expectedSize;
				vint count = itemSource->GetCount();
				vint columnCount = viewBounds.Width() / itemSize.x;
				vint rowCount = count / columnCount;
				if (count % columnCount != 0) rowCount++;

				if (columnCount == 0) columnCount = 1;
				if (rowCount == 0) rowCount = 1;
				return Size(
					CalculateAdoptedSize(expectedSize.x, columnCount, itemSize.x),
					CalculateAdoptedSize(expectedSize.y, rowCount, itemSize.y)
				);
			}

			vint GuiRepeatFixedSizeMultiColumnItemComposition::FindItemByVirtualKeyDirection(vint itemIndex, compositions::KeyDirection key)
			{
				vint count = itemSource->GetCount();
				if (itemIndex < 0 || itemIndex >= count) return -1;
				vint columnCount = viewBounds.Width() / itemSize.x;
				if (columnCount == 0) columnCount = 1;
				vint rowCount = viewBounds.Height() / itemSize.y;
				if (rowCount == 0) rowCount = 1;

				switch (key)
				{
				case KeyDirection::Up:
					itemIndex -= columnCount;
					break;
				case KeyDirection::Down:
					itemIndex += columnCount;
					break;
				case KeyDirection::Left:
					itemIndex--;
					break;
				case KeyDirection::Right:
					itemIndex++;
					break;
				case KeyDirection::Home:
					itemIndex = 0;
					break;
				case KeyDirection::End:
					itemIndex = count;
					break;
				case KeyDirection::PageUp:
					itemIndex -= columnCount * rowCount;
					break;
				case KeyDirection::PageDown:
					itemIndex += columnCount * rowCount;
					break;
				case KeyDirection::PageLeft:
					itemIndex -= itemIndex % columnCount;
					break;
				case KeyDirection::PageRight:
					itemIndex += columnCount - itemIndex % columnCount - 1;
					break;
				default:
					return -1;
				}

				if (itemIndex < 0) return 0;
				else if (itemIndex >= count) return count - 1;
				else return itemIndex;
			}

			VirtualRepeatEnsureItemVisibleResult GuiRepeatFixedSizeMultiColumnItemComposition::EnsureItemVisible(vint itemIndex)
			{
				if (!itemSource) return VirtualRepeatEnsureItemVisibleResult::NotMoved;
				if (itemIndex < 0 || itemIndex >= itemSource->GetCount())
				{
					return VirtualRepeatEnsureItemVisibleResult::ItemNotExists;
				}
				bool moved = false;
				while (true)
				{
					vint rowHeight = itemSize.y;
					vint columnCount = viewBounds.Width() / itemSize.x;
					if (columnCount == 0) columnCount = 1;
					vint rowIndex = itemIndex / columnCount;

					vint top = rowIndex * rowHeight;
					vint bottom = top + rowHeight;

					if (viewBounds.Height() < rowHeight)
					{
						if (viewBounds.Top() < bottom && top < viewBounds.Bottom())
						{
							break;
						}
					}

					Point location = viewBounds.LeftTop();
					if (top < viewBounds.Top())
					{
						location.y = top;
					}
					else if (viewBounds.Bottom() < bottom)
					{
						location.y = bottom - viewBounds.Height();
					}
					else
					{
						break;
					}

					auto oldLeftTop = viewBounds.LeftTop();
					Layout_UpdateViewLocation(location);
					moved |= viewBounds.LeftTop() != oldLeftTop;
					if (viewBounds.LeftTop() != location) break;
				}
				return moved ? VirtualRepeatEnsureItemVisibleResult::Moved : VirtualRepeatEnsureItemVisibleResult::NotMoved;
			}

/***********************************************************************
GuiRepeatFixedHeightMultiColumnItemComposition
***********************************************************************/

			void GuiRepeatFixedHeightMultiColumnItemComposition::FixColumnWidth(vint index)
			{
				vint c = index / pi_rows - pi_firstColumn;
				vint r = index % pi_rows;
				vint w = pi_visibleItemWidths[index - pi_firstColumn * pi_rows];

				if (r == 0)
				{
					while (pi_visibleColumnWidths.Count() <= c) pi_visibleColumnWidths.Add(0);
					while (pi_visibleColumnOffsets.Count() <= c) pi_visibleColumnOffsets.Add(0);

					pi_visibleColumnWidths[c] = w;
					if (c == 0)
					{
						pi_visibleColumnOffsets[c] = 0;
					}
					else
					{
						pi_visibleColumnOffsets[c] = pi_visibleColumnOffsets[c - 1] + pi_visibleColumnWidths[c - 1];
					}
				}
				else
				{
					if (pi_visibleColumnWidths[c] < w)
					{
						pi_visibleColumnWidths[c] = w;
					}
				}
			}

			void GuiRepeatFixedHeightMultiColumnItemComposition::Layout_BeginPlaceItem(bool firstPhase, Rect newBounds, vint& newStartIndex)
			{
				if (firstPhase)
				{
					pi_firstColumn = newBounds.Width() == 0 ? 0 : newBounds.x1 / newBounds.Width();
					pi_itemHeight = itemHeight;

					pi_visibleItemWidths.Clear();
					pi_visibleColumnWidths.Clear();
					pi_visibleColumnOffsets.Clear();
					pi_rows = newBounds.Height() / itemHeight;
					if (pi_rows < 1) pi_rows = 1;

					if (pi_firstColumn < 0)
					{
						pi_firstColumn = 0;
					}
					else if (pi_firstColumn * pi_rows >= itemSource->GetCount())
					{
						pi_firstColumn = (itemSource->GetCount() + pi_rows - 1) / pi_rows - 1;
					}

					newStartIndex = pi_firstColumn * pi_rows;
				}
			}

			VirtualRepeatPlaceItemResult GuiRepeatFixedHeightMultiColumnItemComposition::Layout_PlaceItem(bool firstPhase, bool newCreatedStyle, vint index, ItemStyleRecord style, Rect viewBounds, Rect& bounds, Margin& alignmentToParent)
			{
#define ERROR_MESSAGE_INTERNAL_ERROR L"vl::presentation::compositions::GuiRepeatFixedHeightMultiColumnItemComposition::Layout_PlaceItem(...)#Internal error."

				vint visibleColumn = index / pi_rows - pi_firstColumn;
				vint visibleRow = index % pi_rows;

				if (firstPhase)
				{
					Size styleSize = Layout_GetStylePreferredSize(style);
					if (pi_itemHeight < styleSize.y)
					{
						pi_itemHeight = styleSize.y;
						vint newRows = viewBounds.Height() / pi_itemHeight;
						if (newRows != pi_rows)
						{
							CHECK_ERROR(newRows < pi_rows, ERROR_MESSAGE_INTERNAL_ERROR);
							vint oldFirstIndex = pi_firstColumn * pi_rows;
							pi_rows = newRows > 0 ? newRows : 1;
							vint newFirstIndex = pi_firstColumn * pi_rows;

							if (oldFirstIndex == newFirstIndex)
							{
								for (vint i = newFirstIndex; i < index; i++)
								{
									FixColumnWidth(i + newFirstIndex);
								}
							}
							else
							{
								CHECK_ERROR(oldFirstIndex > newFirstIndex, ERROR_MESSAGE_INTERNAL_ERROR);
								return VirtualRepeatPlaceItemResult::Restart;
							}

							visibleColumn = index / pi_rows - pi_firstColumn;
							visibleRow = index % pi_rows;
						}
					}

					pi_visibleItemWidths.Add(styleSize.x);
					FixColumnWidth(index);
				}

				vint x = viewBounds.x1 + pi_visibleColumnOffsets[visibleColumn];
				vint y = pi_itemHeight * visibleRow;
				vint w = pi_visibleItemWidths[index - pi_firstColumn * pi_rows];
				bounds = Rect({ x,y }, { w,pi_itemHeight });

				if (visibleRow == pi_rows - 1 && pi_visibleColumnOffsets[visibleColumn] + pi_visibleColumnWidths[visibleColumn] >= viewBounds.Width())
				{
					return VirtualRepeatPlaceItemResult::HitLastItem;
				}
				else
				{
					return VirtualRepeatPlaceItemResult::None;
				}
#undef ERROR_MESSAGE_INTERNAL_ERROR
			}

			VirtualRepeatEndPlaceItemResult GuiRepeatFixedHeightMultiColumnItemComposition::Layout_EndPlaceItem(bool firstPhase, Rect newBounds, vint newStartIndex)
			{
				if (firstPhase)
				{
					bool itemHeightUpdated = pi_itemHeight != itemHeight;

					firstColumn = pi_firstColumn;
					itemHeight = pi_itemHeight;
					if (pi_visibleColumnOffsets.Count() <= 1)
					{
						fullVisibleColumns = pi_visibleColumnOffsets.Count();
					}
					else
					{
						vint c = pi_visibleColumnOffsets.Count() - 1;
						vint x = pi_visibleColumnOffsets[c] + pi_visibleColumnWidths[c];
						if (x <= viewBounds.Width())
						{
							fullVisibleColumns = c + 1;
						}
						else
						{
							fullVisibleColumns = c;
						}
					}

					if (itemHeightUpdated)
					{
						return VirtualRepeatEndPlaceItemResult::TotalSizeUpdated;
					}
				}
				return VirtualRepeatEndPlaceItemResult::None;
			}

			void GuiRepeatFixedHeightMultiColumnItemComposition::Layout_EndLayout(bool totalSizeUpdated)
			{
			}

			void GuiRepeatFixedHeightMultiColumnItemComposition::Layout_InvalidateItemSizeCache()
			{
				itemHeight = 1;
			}

			void GuiRepeatFixedHeightMultiColumnItemComposition::Layout_CalculateTotalSize(Size& full, Size& minimum)
			{
				if (!itemSource || itemSource->GetCount() == 0)
				{
					full = minimum = Size(0, 0);
					return;
				}

				vint rows = viewBounds.Height() / itemHeight;
				if (rows < 1) rows = 1;
				vint columns = (itemSource->GetCount() + rows - 1) / rows;

				vint w = viewBounds.Width() * (columns + 1);
				vint h = rows * itemHeight;
				full = Size(w, h);
				minimum = Size(w, 0);
			}

			Size GuiRepeatFixedHeightMultiColumnItemComposition::Layout_GetAdoptedSize(Size expectedSize)
			{
				if (!itemSource) return expectedSize;
				vint count = itemSource->GetCount();
				vint rowCount = viewBounds.Height() / itemHeight;
				if (rowCount > count) rowCount = count;
				if (rowCount == 0) rowCount = 1;
				return Size(expectedSize.x, CalculateAdoptedSize(expectedSize.y, rowCount, itemHeight));
			}

			vint GuiRepeatFixedHeightMultiColumnItemComposition::FindItemByVirtualKeyDirection(vint itemIndex, compositions::KeyDirection key)
			{
				vint count = itemSource->GetCount();
				if (itemIndex < 0 || itemIndex >= count) return -1;
				vint rowCount = viewBounds.Height() / itemHeight;
				if (rowCount == 0) rowCount = 1;

				switch (key)
				{
				case KeyDirection::Up:
					itemIndex--;
					break;
				case KeyDirection::Down:
					itemIndex++;
					break;
				case KeyDirection::Left:
					itemIndex -= rowCount;
					break;
				case KeyDirection::Right:
					itemIndex += rowCount;
					break;
				case KeyDirection::Home:
					itemIndex = 0;
					break;
				case KeyDirection::End:
					itemIndex = count;
					break;
				case KeyDirection::PageUp:
					itemIndex -= itemIndex % rowCount;
					break;
				case KeyDirection::PageDown:
					itemIndex += rowCount - itemIndex % rowCount - 1;
					break;
				default:
					return -1;
				}

				if (itemIndex < 0) return 0;
				else if (itemIndex >= count) return count - 1;
				else return itemIndex;
			}

			VirtualRepeatEnsureItemVisibleResult GuiRepeatFixedHeightMultiColumnItemComposition::EnsureItemVisible(vint itemIndex)
			{
				if (!itemSource) return VirtualRepeatEnsureItemVisibleResult::NotMoved;
				if (itemIndex < 0 || itemIndex >= itemSource->GetCount())
				{
					return VirtualRepeatEnsureItemVisibleResult::ItemNotExists;
				}
				bool moved = false;
				while (true)
				{
					vint rowCount = viewBounds.Height() / itemHeight;
					if (rowCount == 0) rowCount = 1;
					vint column = itemIndex / rowCount;
					Point location = viewBounds.LeftTop();

					if (column < firstColumn)
					{
						location.x = viewBounds.Width() * column;
					}
					else if (column >= firstColumn + fullVisibleColumns)
					{
						location.x = viewBounds.Width() * (column - fullVisibleColumns + 1);
					}
					else
					{
						break;
					}

					auto oldLeftTop = viewBounds.LeftTop();
					Layout_UpdateViewLocation(location);
					moved |= viewBounds.LeftTop() != oldLeftTop;
					if (viewBounds.LeftTop() != location) break;
				}
				return moved ? VirtualRepeatEnsureItemVisibleResult::Moved : VirtualRepeatEnsureItemVisibleResult::NotMoved;
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSCOMPOSITION\GUIGRAPHICSRESPONSIVECOMPOSITION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace collections;
			using namespace controls;

/***********************************************************************
GuiResponsiveCompositionBase
***********************************************************************/

			void GuiResponsiveCompositionBase::OnParentLineChanged()
			{
				GuiBoundsComposition::OnParentLineChanged();
				GuiResponsiveCompositionBase* responsive = nullptr;
				{
					auto parent = GetParent();
					while (parent)
					{
						if ((responsive = dynamic_cast<GuiResponsiveCompositionBase*>(parent)))
						{
							break;
						}
						parent = parent->GetParent();
					}
				}

				if (responsiveParent != responsive)
				{
					if (responsiveParent)
					{
						responsiveParent->OnResponsiveChildRemoved(this);
						responsiveParent->OnResponsiveChildLevelUpdated();
					}
					responsiveParent = responsive;
					if (responsiveParent)
					{
						responsiveParent->OnResponsiveChildInserted(this);
						responsiveParent->OnResponsiveChildLevelUpdated();
					}
				}
			}

			void GuiResponsiveCompositionBase::OnResponsiveChildInserted(GuiResponsiveCompositionBase* child)
			{
			}

			void GuiResponsiveCompositionBase::OnResponsiveChildRemoved(GuiResponsiveCompositionBase* child)
			{
			}

			void GuiResponsiveCompositionBase::OnResponsiveChildLevelUpdated()
			{
				if (responsiveParent)
				{
					responsiveParent->OnResponsiveChildLevelUpdated();
				}
				else
				{
					InvokeOnCompositionStateChanged();
				}
			}

			GuiResponsiveCompositionBase::GuiResponsiveCompositionBase()
			{
				SetMinSizeLimitation(LimitToElementAndChildren);
				SetPreferredMinSize(Size(1, 1));

				LevelCountChanged.SetAssociatedComposition(this);
				CurrentLevelChanged.SetAssociatedComposition(this);
			}

			ResponsiveDirection GuiResponsiveCompositionBase::GetDirection()
			{
				return direction;
			}

			void GuiResponsiveCompositionBase::SetDirection(ResponsiveDirection value)
			{
				if (direction != value)
				{
					direction = value;
					OnResponsiveChildLevelUpdated();
				}
			}

/***********************************************************************
GuiResponsiveSharedCollection
***********************************************************************/

			void GuiResponsiveSharedCollection::BeforeInsert(vint index, controls::GuiControl* const& value)
			{
				CHECK_ERROR(!value->GetBoundsComposition()->GetParent(), L"GuiResponsiveSharedCollection::BeforeInsert(vint, GuiResponsiveSharedCollection* const&)#Cannot insert a shared control that is currently in use.");
			}

			void GuiResponsiveSharedCollection::AfterInsert(vint index, controls::GuiControl* const& value)
			{
				view->OnResponsiveChildLevelUpdated();
			}

			void GuiResponsiveSharedCollection::BeforeRemove(vint index, controls::GuiControl* const& value)
			{
				CHECK_ERROR(!value->GetBoundsComposition()->GetParent(), L"GuiResponsiveSharedCollection::BeforeRemove(vint, GuiResponsiveSharedCollection* const&)#Cannot remove a shared control that is currently in use.");
			}

			void GuiResponsiveSharedCollection::AfterRemove(vint index, vint count)
			{
				view->OnResponsiveChildLevelUpdated();
			}

			GuiResponsiveSharedCollection::GuiResponsiveSharedCollection(GuiResponsiveViewComposition* _view)
				:view(_view)
			{
			}

/***********************************************************************
GuiResponsiveViewCollection
***********************************************************************/

			void GuiResponsiveViewCollection::BeforeInsert(vint index, GuiResponsiveCompositionBase* const& value)
			{
				CHECK_ERROR(!value->GetParent(), L"GuiResponsiveViewCollection::BeforeRemove(vint, GuiResponsiveCompositionBase* const&)#Cannot insert a view that is currently in use.");
			}

			void GuiResponsiveViewCollection::AfterInsert(vint index, GuiResponsiveCompositionBase* const& value)
			{
				if (!view->currentView)
				{
					view->skipUpdatingLevels = true;
					view->currentView = value;
					view->currentView->SetAlignmentToParent(Margin(0, 0, 0, 0));
					view->AddChild(view->currentView);
					view->skipUpdatingLevels = false;
				}
				view->OnResponsiveChildLevelUpdated();
			}

			void GuiResponsiveViewCollection::BeforeRemove(vint index, GuiResponsiveCompositionBase* const& value)
			{
				CHECK_ERROR(!value->GetParent(), L"GuiResponsiveViewCollection::BeforeRemove(vint, GuiResponsiveCompositionBase* const&)#Cannot remove a view that is currently in use.");
			}

			void GuiResponsiveViewCollection::AfterRemove(vint index, vint count)
			{
				view->OnResponsiveChildLevelUpdated();
			}

			GuiResponsiveViewCollection::GuiResponsiveViewCollection(GuiResponsiveViewComposition* _view)
				:view(_view)
			{
			}

/***********************************************************************
GuiResponsiveSharedComposition
***********************************************************************/

			void GuiResponsiveSharedComposition::SetSharedControl()
			{
				if (shared && view && !view->destructing)
				{
					auto sharedParent = shared->GetBoundsComposition()->GetParent();
					CHECK_ERROR(view->sharedControls.Contains(shared), L"GuiResponsiveSharedComposition::SetSharedControl()#The specified shared control is not in GuiResponsiveViewComposition::GetSharedControls().");
					CHECK_ERROR(!sharedParent || sharedParent == this, L"GuiResponsiveSharedComposition::SetSharedControl()#The specified shared control has not been released. This usually means this control is not in GuiResponsiveViewComposition::GetSharedControls().");

					if (!sharedParent)
					{
						shared->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
						AddChild(shared->GetBoundsComposition());
						view->usedSharedControls.Add(shared);
					}
				}
			}

			void GuiResponsiveSharedComposition::OnParentLineChanged()
			{
				GuiBoundsComposition::OnParentLineChanged();
				if (view && view->destructing)
				{
					return;
				}

				GuiResponsiveViewComposition* currentView = nullptr;
				{
					auto parent = GetParent();
					while (parent)
					{
						if ((currentView = dynamic_cast<GuiResponsiveViewComposition*>(parent)))
						{
							break;
						}
						parent = parent->GetParent();
					}
				}

				if (currentView != view && view && shared)
				{
					RemoveChild(shared->GetBoundsComposition());
					view->usedSharedControls.Remove(shared);
				}
				view = currentView;

				SetSharedControl();
			}

			GuiResponsiveSharedComposition::GuiResponsiveSharedComposition()
			{
				SetMinSizeLimitation(LimitToElementAndChildren);
			}

			controls::GuiControl* GuiResponsiveSharedComposition::GetShared()
			{
				return shared;
			}

			void GuiResponsiveSharedComposition::SetShared(controls::GuiControl* value)
			{
				if (shared != value)
				{
					CHECK_ERROR(!shared || !shared->GetBoundsComposition()->GetParent(), L"GuiResponsiveSharedComposition::SetShared(GuiControl*)#Cannot replace a shared control that is currently in use.");
					shared = value;
					SetSharedControl();
				}
			}

/***********************************************************************
GuiResponsiveViewComposition
***********************************************************************/

			bool GuiResponsiveViewComposition::CalculateLevelCount()
			{
				vint old = levelCount;
				if (views.Count() == 0)
				{
					levelCount = 1;
				}
				else
				{
					levelCount = 0;
					// TODO: (enumerable) foreach
					for (vint i = 0; i < views.Count(); i++)
					{
						auto view = views[i];
						if (((vint)direction & (vint)view->GetDirection()) != 0)
						{
							levelCount += view->GetLevelCount();
						}
						else
						{
							levelCount += 1;
						}
					}
				}

				if (old != levelCount)
				{
					LevelCountChanged.Execute(GuiEventArgs(this));
					return true;
				}
				return false;
			}

			bool GuiResponsiveViewComposition::CalculateCurrentLevel()
			{
				vint old = currentLevel;
				currentLevel = 0;
				// TODO: (enumerable) foreach:reversed
				for (vint i = views.Count() - 1; i >= 0; i--)
				{
					auto view = views[i];
					if (((vint)direction & (vint)view->GetDirection()) != 0)
					{
						if (currentView == view)
						{
							currentLevel += view->GetCurrentLevel() + 1;
							break;
						}
						else
						{
							currentLevel += view->GetLevelCount();
						}
					}
					else
					{
						currentLevel++;
					}
				}
				currentLevel--;

				if (old != currentLevel)
				{
					CurrentLevelChanged.Execute(GuiEventArgs(this));
					return true;
				}
				return false;
			}

			void GuiResponsiveViewComposition::OnResponsiveChildLevelUpdated()
			{
				if (!skipUpdatingLevels)
				{
					CalculateLevelCount();
					CalculateCurrentLevel();
					GuiResponsiveCompositionBase::OnResponsiveChildLevelUpdated();
				}
			}

			GuiResponsiveViewComposition::GuiResponsiveViewComposition()
				:sharedControls(this)
				, views(this)
			{
				BeforeSwitchingView.SetAssociatedComposition(this);
			}

			GuiResponsiveViewComposition::~GuiResponsiveViewComposition()
			{
				destructing = true;

				for (auto view : views)
				{
					if (view != currentView)
					{
						SafeDeleteComposition(view);
					}
				}

				for (auto shared : From(sharedControls).Except(usedSharedControls))
				{
					SafeDeleteControl(shared);
				}
			}

			vint GuiResponsiveViewComposition::GetLevelCount()
			{
				return levelCount;
			}

			vint GuiResponsiveViewComposition::GetCurrentLevel()
			{
				return currentLevel;
			}

			bool GuiResponsiveViewComposition::LevelDown()
			{
				skipUpdatingLevels = true;
				if (((vint)direction & (vint)currentView->GetDirection()) != 0 && !currentView->LevelDown())
				{
					vint index = views.IndexOf(currentView);
					if (index < views.Count() - 1)
					{
						RemoveChild(currentView);
						currentView = views[index + 1];
						currentView->SetAlignmentToParent(Margin(0, 0, 0, 0));
						{
							GuiItemEventArgs arguments(this);
							arguments.itemIndex = views.IndexOf(currentView);
							BeforeSwitchingView.Execute(arguments);
						}
						AddChild(currentView);
					}
				}
				skipUpdatingLevels = false;
				
				auto x = CalculateLevelCount();
				auto y = CalculateCurrentLevel();
				if (!x && !y) return false;
				InvokeOnCompositionStateChanged();
				return true;
			}

			bool GuiResponsiveViewComposition::LevelUp()
			{
				skipUpdatingLevels = true;
				if (((vint)direction & (vint)currentView->GetDirection()) != 0 && !currentView->LevelUp())
				{
					vint index = views.IndexOf(currentView);
					if (index > 0)
					{
						RemoveChild(currentView);
						currentView = views[index - 1];
						currentView->SetAlignmentToParent(Margin(0, 0, 0, 0));
						{
							GuiItemEventArgs arguments(this);
							arguments.itemIndex = views.IndexOf(currentView);
							BeforeSwitchingView.Execute(arguments);
						}
						AddChild(currentView);
					}
				}
				skipUpdatingLevels = false;

				auto x = CalculateLevelCount();
				auto y = CalculateCurrentLevel();
				if (!x && !y) return false;
				InvokeOnCompositionStateChanged();
				return true;
			}

			GuiResponsiveCompositionBase* GuiResponsiveViewComposition::GetCurrentView()
			{
				return currentView;
			}

			collections::ObservableListBase<controls::GuiControl*>& GuiResponsiveViewComposition::GetSharedControls()
			{
				return sharedControls;
			}

			collections::ObservableListBase<GuiResponsiveCompositionBase*>& GuiResponsiveViewComposition::GetViews()
			{
				return views;
			}

/***********************************************************************
GuiResponsiveFixedComposition
***********************************************************************/

			void GuiResponsiveFixedComposition::OnResponsiveChildLevelUpdated()
			{
				InvokeOnCompositionStateChanged();
			}

			vint GuiResponsiveFixedComposition::GetLevelCount()
			{
				return 1;
			}

			vint GuiResponsiveFixedComposition::GetCurrentLevel()
			{
				return 0;
			}

			bool GuiResponsiveFixedComposition::LevelDown()
			{
				return false;
			}

			bool GuiResponsiveFixedComposition::LevelUp()
			{
				return false;
			}

/***********************************************************************
GuiResponsiveStackComposition
***********************************************************************/

#define DEFINE_AVAILABLE \
			auto availables = From(responsiveChildren) \
				.Where([=, this](GuiResponsiveCompositionBase* child) \
				{ \
					return ((vint)direction & (vint)child->GetDirection()) != 0; \
				}) \

			bool GuiResponsiveStackComposition::CalculateLevelCount()
			{
				vint old = levelCount;
				DEFINE_AVAILABLE;
				if (availables.IsEmpty())
				{
					levelCount = 1;
				}
				else
				{
					levelCount = availables
						.Select([](GuiResponsiveCompositionBase* child)
						{
							return child->GetLevelCount() - 1;
						})
						.Aggregate([](vint a, vint b)
						{
							return a + b;
						}) + 1;
				}

				if (old != levelCount)
				{
					LevelCountChanged.Execute(GuiEventArgs(this));
					return true;
				}
				return false;
			}

			bool GuiResponsiveStackComposition::CalculateCurrentLevel()
			{
				vint old = currentLevel;
				DEFINE_AVAILABLE;
				if (availables.IsEmpty())
				{
					currentLevel = 0;
				}
				else
				{
					currentLevel = availables
						.Select([](GuiResponsiveCompositionBase* child)
						{
							return child->GetCurrentLevel();
						})
						.Aggregate([](vint a, vint b)
						{
							return a + b;
						});
				}

				if (old != currentLevel)
				{
					CurrentLevelChanged.Execute(GuiEventArgs(this));
					return true;
				}
				return false;
			}

			void GuiResponsiveStackComposition::OnResponsiveChildInserted(GuiResponsiveCompositionBase* child)
			{
				responsiveChildren.Add(child);
			}

			void GuiResponsiveStackComposition::OnResponsiveChildRemoved(GuiResponsiveCompositionBase* child)
			{
				responsiveChildren.Remove(child);
			}

			void GuiResponsiveStackComposition::OnResponsiveChildLevelUpdated()
			{
				CalculateLevelCount();
				CalculateCurrentLevel();
				GuiResponsiveCompositionBase::OnResponsiveChildLevelUpdated();
			}

			bool GuiResponsiveStackComposition::ChangeLevel(bool levelDown)
			{
				DEFINE_AVAILABLE;

				SortedList<GuiResponsiveCompositionBase*> ignored;
				while (true)
				{
					GuiResponsiveCompositionBase* selected = nullptr;
					vint size = 0;

					for (auto child : availables)
					{
						if (!ignored.Contains(child))
						{
							Size childSize = child->GetCachedBounds().GetSize();
							vint childSizeToCompare =
								direction == ResponsiveDirection::Horizontal ? childSize.x :
								direction == ResponsiveDirection::Vertical ? childSize.y :
								childSize.x * childSize.y;

							if (!selected || (levelDown ? size < childSizeToCompare : size > childSizeToCompare))
							{
								selected = child;
								size = childSizeToCompare;
							}
						}
					}

					if (!selected)
					{
						break;
					}
					else if (levelDown ? selected->LevelDown() : selected->LevelUp())
					{
						break;
					}
					else
					{
						ignored.Add(selected);
					}
				}

				if (!CalculateCurrentLevel()) return false;
				InvokeOnCompositionStateChanged();
				return true;
			}

			vint GuiResponsiveStackComposition::GetLevelCount()
			{
				return levelCount;
			}

			vint GuiResponsiveStackComposition::GetCurrentLevel()
			{
				return currentLevel;
			}

			bool GuiResponsiveStackComposition::LevelDown()
			{
				return ChangeLevel(true);
			}

			bool GuiResponsiveStackComposition::LevelUp()
			{
				return ChangeLevel(false);
			}

/***********************************************************************
GuiResponsiveGroupComposition
***********************************************************************/

			bool GuiResponsiveGroupComposition::CalculateLevelCount()
			{
				vint old = levelCount;
				DEFINE_AVAILABLE;
				if (availables.IsEmpty())
				{
					levelCount = 1;
				}
				else
				{
					levelCount = availables
						.Select([](GuiResponsiveCompositionBase* child)
						{
							return child->GetLevelCount();
						})
						.Max();
				}

				if (old != levelCount)
				{
					LevelCountChanged.Execute(GuiEventArgs(this));
					return true;
				}
				return false;
			}

			bool GuiResponsiveGroupComposition::CalculateCurrentLevel()
			{
				vint old = currentLevel;
				DEFINE_AVAILABLE;
				if (availables.IsEmpty())
				{
					currentLevel = 0;
				}
				else
				{
					currentLevel = availables
						.Select([](GuiResponsiveCompositionBase* child)
						{
							return child->GetCurrentLevel();
						})
						.Max();
				}

				if (old != currentLevel)
				{
					CurrentLevelChanged.Execute(GuiEventArgs(this));
					return true;
				}
				return false;
			}

			void GuiResponsiveGroupComposition::OnResponsiveChildInserted(GuiResponsiveCompositionBase* child)
			{
				responsiveChildren.Add(child);
			}

			void GuiResponsiveGroupComposition::OnResponsiveChildRemoved(GuiResponsiveCompositionBase* child)
			{
				responsiveChildren.Remove(child);
			}

			void GuiResponsiveGroupComposition::OnResponsiveChildLevelUpdated()
			{
				CalculateLevelCount();
				CalculateCurrentLevel();
				GuiResponsiveCompositionBase::OnResponsiveChildLevelUpdated();
			}

			vint GuiResponsiveGroupComposition::GetLevelCount()
			{
				return levelCount;
			}

			vint GuiResponsiveGroupComposition::GetCurrentLevel()
			{
				return currentLevel;
			}

			bool GuiResponsiveGroupComposition::LevelDown()
			{
				DEFINE_AVAILABLE;
				vint level = currentLevel;
				for (auto child : availables)
				{
					if (child->GetCurrentLevel() >= level)
					{
						if (!child->LevelDown())
						{
							break;
						}
					}
				}

				if (!CalculateCurrentLevel()) return false;
				InvokeOnCompositionStateChanged();
				return true;
			}

			bool GuiResponsiveGroupComposition::LevelUp()
			{
				DEFINE_AVAILABLE;
				vint level = currentLevel;
				for (auto child : availables)
				{
					while (child->GetCurrentLevel() <= level)
					{
						if (!child->LevelUp())
						{
							break;
						}
					}
				}

				if (!CalculateCurrentLevel()) return false;
				InvokeOnCompositionStateChanged();
				return true;
			}

#undef DEFINE_AVAILABLE

/***********************************************************************
GuiResponsiveContainerComposition
***********************************************************************/

			std::strong_ordering GuiResponsiveContainerComposition::Layout_CompareSize(Size first, Size second)
			{
				auto ordX = testX ? first.x <=> second.x : std::strong_ordering::equivalent;
				auto ordY = testY ? first.y <=> second.y : std::strong_ordering::equivalent;

				if (ordX == std::strong_ordering::less || ordY == std::strong_ordering::less)
				{
					return std::strong_ordering::less;
				}
				if (ordX == std::strong_ordering::greater || ordY == std::strong_ordering::greater)
				{
					return std::strong_ordering::greater;
				}
				return std::strong_ordering::equivalent;
			}

			void GuiResponsiveContainerComposition::Layout_AdjustLevelUp(Size containerSize)
			{
				while (true)
				{
					if (responsiveTarget->GetCurrentLevel() == responsiveTarget->GetLevelCount() - 1) break;
					if (Layout_CompareSize(minSizeLowerBound, minSizeUpperBound) == std::strong_ordering::less)
					{
						if (Layout_CompareSize(containerSize, minSizeUpperBound) == std::strong_ordering::less) break;
					}
					else
					{
						if (Layout_CompareSize(containerSize, minSizeUpperBound) != std::strong_ordering::greater) break;
					}

					if (!responsiveTarget->LevelUp()) break;
					responsiveTarget->Layout_UpdateMinSize();
					minSizeUpperBound = responsiveTarget->GetCachedMinSize();
					if (Layout_CompareSize(containerSize, minSizeUpperBound) == std::strong_ordering::less)
					{
						responsiveTarget->LevelDown();
						responsiveTarget->Layout_UpdateMinSize();
						break;
					}
					minSizeLowerBound = minSizeUpperBound;
				}
			}

			void GuiResponsiveContainerComposition::Layout_AdjustLevelDown(Size containerSize)
			{
				while (true)
				{
					if (responsiveTarget->GetCurrentLevel() == 0) break;
					if (Layout_CompareSize(containerSize, minSizeLowerBound) != std::strong_ordering::less) break;

					if (!responsiveTarget->LevelDown()) break;
					responsiveTarget->Layout_UpdateMinSize();
					minSizeUpperBound = minSizeLowerBound;
					minSizeLowerBound = responsiveTarget->GetCachedMinSize();
				}
			}

			Rect GuiResponsiveContainerComposition::Layout_CalculateBounds(Size parentSize)
			{
				auto bounds = GuiBoundsComposition::Layout_CalculateBounds(parentSize);

				if (responsiveTarget)
				{
					bool needAdjust = false;
					auto containerSize = bounds.GetSize();
					auto ordering = std::strong_ordering::equivalent;

					if (containerSize != cachedBounds.GetSize())
					{
						ordering = Layout_CompareSize(containerSize, cachedBounds.GetSize());
						needAdjust = true;
					}

					if (responsiveTarget)
					{
						if (responsiveTarget->GetCachedMinSize() != minSizeLowerBound)
						{
							minSizeLowerBound = responsiveTarget->GetCachedMinSize();
							if (minSizeUpperBound.x < minSizeLowerBound.x) minSizeUpperBound.x = minSizeLowerBound.x;
							if (minSizeUpperBound.y < minSizeLowerBound.y) minSizeUpperBound.y = minSizeLowerBound.y;
						}

						if (Layout_CompareSize(containerSize, minSizeLowerBound) == std::strong_ordering::less)
						{
							ordering = std::strong_ordering::less;
							needAdjust = true;
						}
					}

					if (needAdjust)
					{
						if (ordering == std::strong_ordering::less)
						{
							Layout_AdjustLevelDown(containerSize);
						}
						else if (ordering == std::strong_ordering::greater)
						{
							Layout_AdjustLevelUp(containerSize);
						}
					}
				}

				return bounds;
			}

			GuiResponsiveContainerComposition::GuiResponsiveContainerComposition()
			{
			}

			GuiResponsiveCompositionBase* GuiResponsiveContainerComposition::GetResponsiveTarget()
			{
				return responsiveTarget;
			}

			void GuiResponsiveContainerComposition::SetResponsiveTarget(GuiResponsiveCompositionBase* value)
			{
				if (responsiveTarget != value)
				{
					if (responsiveTarget)
					{
						RemoveChild(responsiveTarget);
					}

					responsiveTarget = value;

					if (responsiveTarget)
					{
						responsiveTarget->SetAlignmentToParent(Margin(0, 0, 0, 0));
						while (responsiveTarget->LevelUp());
						AddChild(responsiveTarget);

						responsiveTarget->Layout_UpdateMinSize();
						minSizeUpperBound = responsiveTarget->GetCachedMinSize();
						minSizeLowerBound = responsiveTarget->GetCachedMinSize();
						testX = (vint)responsiveTarget->GetDirection() & (vint)ResponsiveDirection::Horizontal;
						testY = (vint)responsiveTarget->GetDirection() & (vint)ResponsiveDirection::Vertical;
						Layout_AdjustLevelDown(cachedBounds.GetSize());
					}
					else
					{
						minSizeUpperBound = {};
						minSizeLowerBound = {};
						testX = false;
						testY = false;
					}
				}
			}
		}
	}
}


/***********************************************************************
.\GRAPHICSCOMPOSITION\GUIGRAPHICSSHAREDSIZECOMPOSITION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace reflection::description;
			using namespace collections;
			using namespace controls;
			using namespace elements;

/***********************************************************************
GuiSharedSizeItemComposition
***********************************************************************/

			void GuiSharedSizeItemComposition::OnParentLineChanged()
			{
				GuiBoundsComposition::OnParentLineChanged();
				if (parentRoot)
				{
					parentRoot->childItems.Remove(this);
					parentRoot = nullptr;
				}

				auto current = GetParent();
				while (current)
				{
					if (auto item = dynamic_cast<GuiSharedSizeItemComposition*>(current))
					{
						break;
					}
					else if (auto root = dynamic_cast<GuiSharedSizeRootComposition*>(current))
					{
						parentRoot = root;
						break;
					}
					current = current->GetParent();
				}

				if (parentRoot)
				{
					parentRoot->childItems.Add(this);
				}
			}

			Size GuiSharedSizeItemComposition::Layout_CalculateMinSize()
			{
				if (parentRoot)
				{
					return cachedMinSize;
				}
				else
				{
					return GuiBoundsComposition::Layout_CalculateMinSize();
				}
			}

			Size GuiSharedSizeItemComposition::Layout_CalculateOriginalMinSize()
			{
				return GuiBoundsComposition::Layout_CalculateMinSize();
			}

			GuiSharedSizeItemComposition::GuiSharedSizeItemComposition()
			{
				SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
			}

			const WString& GuiSharedSizeItemComposition::GetGroup()
			{
				return group;
			}

			void GuiSharedSizeItemComposition::SetGroup(const WString& value)
			{
				if (group != value)
				{
					group = value;
					InvokeOnCompositionStateChanged();
				}
			}

			bool GuiSharedSizeItemComposition::GetSharedWidth()
			{
				return sharedWidth;
			}

			void GuiSharedSizeItemComposition::SetSharedWidth(bool value)
			{
				if (sharedWidth != value)
				{
					sharedWidth = value;
					InvokeOnCompositionStateChanged();
				}
			}

			bool GuiSharedSizeItemComposition::GetSharedHeight()
			{
				return sharedHeight;
			}

			void GuiSharedSizeItemComposition::SetSharedHeight(bool value)
			{
				if (sharedHeight != value)
				{
					sharedHeight = value;
					InvokeOnCompositionStateChanged();
				}
			}

/***********************************************************************
GuiSharedSizeRootComposition
***********************************************************************/

			void GuiSharedSizeRootComposition::AddSizeComponent(collections::Dictionary<WString, vint>& sizes, const WString& group, vint sizeComponent)
			{
				vint index = sizes.Keys().IndexOf(group);
				if (index == -1)
				{
					sizes.Add(group, sizeComponent);
				}
				else if (sizes.Values().Get(index) < sizeComponent)
				{
					sizes.Set(group, sizeComponent);
				}
			}

			void GuiSharedSizeRootComposition::CalculateOriginalMinSizes()
			{
				for (auto item : childItems)
				{
					item->originalMinSize = item->Layout_CalculateOriginalMinSize();
				}
			}

			void GuiSharedSizeRootComposition::CollectSizes(collections::Dictionary<WString, vint>& widths, collections::Dictionary<WString, vint>& heights)
			{
				for (auto item : childItems)
				{
					auto group = item->GetGroup();
					if (item->GetSharedWidth())
					{
						AddSizeComponent(widths, group, item->originalMinSize.x);
					}
					if (item->GetSharedHeight())
					{
						AddSizeComponent(heights, group, item->originalMinSize.y);
					}
				}
			}

			void GuiSharedSizeRootComposition::AlignSizes(collections::Dictionary<WString, vint>& widths, collections::Dictionary<WString, vint>& heights)
			{
				for (auto item : childItems)
				{
					auto group = item->GetGroup();
					auto size = item->originalMinSize;

					if (item->GetSharedWidth())
					{
						size.x = widths[group];
					}
					if (item->GetSharedHeight())
					{
						size.y = heights[group];
					}

					item->Layout_SetCachedMinSize(size);
				}
			}

			Size GuiSharedSizeRootComposition::Layout_CalculateMinSize()
			{
				itemWidths.Clear();
				itemHeights.Clear();
				CalculateOriginalMinSizes();
				CollectSizes(itemWidths, itemHeights);
				AlignSizes(itemWidths, itemHeights);
				return GuiBoundsComposition::Layout_CalculateMinSize();
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSCOMPOSITION\GUIGRAPHICSSPECIALIZEDCOMPOSITION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{

/***********************************************************************
GuiSideAlignedComposition
***********************************************************************/

			Rect GuiSideAlignedComposition::Layout_CalculateBounds(Size parentSize)
			{
				Rect result;
				if (auto parent = GetParent())
				{
					Rect bounds({}, parentSize);
					vint w = (vint)(bounds.Width() * maxRatio);
					vint h = (vint)(bounds.Height() * maxRatio);
					if (w > maxLength) w = maxLength;
					if (h > maxLength) h = maxLength;
					switch (direction)
					{
					case Left:
					{
						bounds.x2 = bounds.x1 + w;
					}
					break;
					case Top:
					{
						bounds.y2 = bounds.y1 + h;
					}
					break;
					case Right:
					{
						bounds.x1 = bounds.x2 - w;
					}
					break;
					case Bottom:
					{
						bounds.y1 = bounds.y2 - h;
					}
					break;
					}
					result = bounds;
				}
				return result;
			}

			GuiSideAlignedComposition::Direction GuiSideAlignedComposition::GetDirection()
			{
				return direction;
			}

			void GuiSideAlignedComposition::SetDirection(Direction value)
			{
				if (direction != value)
				{
					direction = value;
					InvokeOnCompositionStateChanged();
				}
			}

			vint GuiSideAlignedComposition::GetMaxLength()
			{
				return maxLength;
			}

			void GuiSideAlignedComposition::SetMaxLength(vint value)
			{
				if (value < 0) value = 0;
				if (maxLength != value)
				{
					maxLength = value;
					InvokeOnCompositionStateChanged();
				}
			}

			double GuiSideAlignedComposition::GetMaxRatio()
			{
				return maxRatio;
			}

			void GuiSideAlignedComposition::SetMaxRatio(double value)
			{
				if (value < 0) value = 0; else if (value > 1) value = 1;
				if (maxRatio != value)
				{
					maxRatio = value;
					InvokeOnCompositionStateChanged();
				}
			}

/***********************************************************************
GuiPartialViewComposition
***********************************************************************/

			Rect GuiPartialViewComposition::Layout_CalculateBounds(Size parentSize)
			{
				Rect result;
				if (auto parent = GetParent())
				{
					Rect bounds({}, parentSize);
					vint w = bounds.Width();
					vint h = bounds.Height();
					vint pw = (vint)(wPageSize * w);
					vint ph = (vint)(hPageSize * h);

					vint ow = preferredMinSize.x - pw;
					if (ow < 0) ow = 0;
					vint oh = preferredMinSize.y - ph;
					if (oh < 0) oh = 0;

					w -= ow;
					h -= oh;
					pw += ow;
					ph += oh;

					result = Rect(Point((vint)(wRatio * w), (vint)(hRatio * h)), Size(pw, ph));
				}
				return result;
			}

			double GuiPartialViewComposition::GetWidthRatio()
			{
				return wRatio;
			}

			double GuiPartialViewComposition::GetWidthPageSize()
			{
				return wPageSize;
			}

			double GuiPartialViewComposition::GetHeightRatio()
			{
				return hRatio;
			}

			double GuiPartialViewComposition::GetHeightPageSize()
			{
				return hPageSize;
			}

			void GuiPartialViewComposition::SetWidthRatio(double value)
			{
				if (wRatio != value)
				{
					wRatio = value;
					InvokeOnCompositionStateChanged();
				}
			}

			void GuiPartialViewComposition::SetWidthPageSize(double value)
			{
				if (wPageSize != value)
				{
					wPageSize = value;
					InvokeOnCompositionStateChanged();
				}
			}

			void GuiPartialViewComposition::SetHeightRatio(double value)
			{
				if (hRatio != value)
				{
					hRatio = value;
					InvokeOnCompositionStateChanged();
				}
			}

			void GuiPartialViewComposition::SetHeightPageSize(double value)
			{
				if (hPageSize != value)
				{
					hPageSize = value;
					InvokeOnCompositionStateChanged();
				}
			}
		}
	}
}


/***********************************************************************
.\GRAPHICSCOMPOSITION\GUIGRAPHICSSTACKCOMPOSITION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{

/***********************************************************************
GuiStackComposition
***********************************************************************/

			void GuiStackComposition::Layout_UpdateStackItemMinSizes()
			{
				for (auto item : layout_stackItems)
				{
					item->Layout_SetCachedMinSize(item->Layout_CalculateMinSizeHelper());
				}

				if (!layout_invalid) return;
				layout_invalid = false;

				Point virtualOffset;
				layout_stackItemTotalSize = Size(0, 0);
				for (auto [item, index] : indexed(layout_stackItems))
				{
					Size itemSize = item->GetCachedMinSize();

					switch (direction)
					{
					case GuiStackComposition::Horizontal:
					case GuiStackComposition::ReversedHorizontal:
						{
							if (layout_stackItemTotalSize.y < itemSize.y)
							{
								layout_stackItemTotalSize.y = itemSize.y;
							}
							if (index > 0)
							{
								layout_stackItemTotalSize.x += padding;
							}
							layout_stackItemTotalSize.x += itemSize.x;
						}
						break;
					case GuiStackComposition::Vertical:
					case GuiStackComposition::ReversedVertical:
						{
							if (layout_stackItemTotalSize.x < itemSize.x)
							{
								layout_stackItemTotalSize.x = itemSize.x;
							}
							if (index > 0)
							{
								layout_stackItemTotalSize.y += padding;
							}
							layout_stackItemTotalSize.y += itemSize.y;
						}
						break;
					}

					item->layout_virtualOffset = virtualOffset;
					virtualOffset.x += itemSize.x + padding;
					virtualOffset.y += itemSize.y + padding;
				}
			}

			void GuiStackComposition::Layout_UpdateStackItemBounds(Rect contentBounds)
			{
				if (layout_ensuringVisibleStackItem)
				{
					Rect itemBounds(
						layout_ensuringVisibleStackItem->layout_virtualOffset,
						layout_ensuringVisibleStackItem->GetCachedMinSize()
					);

					switch (direction)
					{
					case Horizontal:
					case ReversedHorizontal:
						if (itemBounds.x1 <= 0)
						{
							layout_adjustment = -itemBounds.x1;
						}
						else
						{
							vint overflow = itemBounds.x2 - contentBounds.x2;
							if (overflow > 0)
							{
								layout_adjustment = -overflow;
							}
						}
						break;
					case Vertical:
					case ReversedVertical:
						if (itemBounds.y1 <= 0)
						{
							layout_adjustment = -itemBounds.y1;
						}
						else
						{
							vint overflow = itemBounds.y2 - contentBounds.y2;
							if (overflow > 0)
							{
								layout_adjustment = -overflow;
							}
						}
						break;
					}
				}

				for (auto item : layout_stackItems)
				{
					item->Layout_SetStackItemBounds(contentBounds, item->layout_virtualOffset);
				}
			}

			void GuiStackComposition::OnChildInserted(GuiGraphicsComposition* child)
			{
				GuiBoundsComposition::OnChildInserted(child);
				GuiStackItemComposition* item = dynamic_cast<GuiStackItemComposition*>(child);
				if (item)
				{
					if (!layout_stackItems.Contains(item))
					{
						layout_stackItems.Add(item);
					}
				}
			}

			void GuiStackComposition::OnChildRemoved(GuiGraphicsComposition* child)
			{
				GuiBoundsComposition::OnChildRemoved(child);
				GuiStackItemComposition* item = dynamic_cast<GuiStackItemComposition*>(child);
				if (item)
				{
					layout_stackItems.Remove(item);
					if (item == layout_ensuringVisibleStackItem)
					{
						layout_ensuringVisibleStackItem = nullptr;
					}
				}
			}

			void GuiStackComposition::OnCompositionStateChanged()
			{
				GuiBoundsComposition::OnCompositionStateChanged();
				layout_invalid = true;
			}

			Size GuiStackComposition::Layout_CalculateMinSize()
			{
				Layout_UpdateStackItemMinSizes();

				Size minStackSize;
				if (GetMinSizeLimitation() == GuiGraphicsComposition::LimitToElementAndChildren)
				{
					if (!layout_ensuringVisibleStackItem || direction == Vertical || direction == ReversedVertical)
					{
						minStackSize.x = layout_stackItemTotalSize.x;
					}
					if (!layout_ensuringVisibleStackItem || direction == Horizontal || direction == ReversedHorizontal)
					{
						minStackSize.y = layout_stackItemTotalSize.y;
					}
				}

				minStackSize.x += extraMargin.left;
				minStackSize.x += extraMargin.right;
				minStackSize.y += extraMargin.top;
				minStackSize.y += extraMargin.bottom;

				Size minClientSize = GuiBoundsComposition::Layout_CalculateMinSize();
				return Size(
					minStackSize.x > minClientSize.x ? minStackSize.x : minClientSize.x,
					minStackSize.y > minClientSize.y ? minStackSize.y : minClientSize.y
					);
				return minStackSize;
			}

			Rect GuiStackComposition::Layout_CalculateBounds(Size parentSize)
			{
				Rect bounds = GuiBoundsComposition::Layout_CalculateBounds(parentSize);
				Rect contentBounds(
					extraMargin.left,
					extraMargin.top,
					bounds.Width() - extraMargin.right,
					bounds.Height() - extraMargin.bottom
				);
				Layout_UpdateStackItemBounds(contentBounds);
				return bounds;
			}

			const GuiStackComposition::ItemCompositionList& GuiStackComposition::GetStackItems()
			{
				return layout_stackItems;
			}

			bool GuiStackComposition::InsertStackItem(vint index, GuiStackItemComposition* item)
			{
				index = layout_stackItems.Insert(index, item);
				if (AddChild(item))
				{
					return true;
				}
				layout_stackItems.RemoveAt(index);
				return false;
			}

			GuiStackComposition::Direction GuiStackComposition::GetDirection()
			{
				return direction;
			}

			void GuiStackComposition::SetDirection(Direction value)
			{
				if (direction != value)
				{
					direction = value;
					InvokeOnCompositionStateChanged();
				}
			}

			vint GuiStackComposition::GetPadding()
			{
				return padding;
			}

			void GuiStackComposition::SetPadding(vint value)
			{
				if (padding != value)
				{
					padding = value;
					InvokeOnCompositionStateChanged();
				}
			}

			Margin GuiStackComposition::GetExtraMargin()
			{
				return extraMargin;
			}

			void GuiStackComposition::SetExtraMargin(Margin value)
			{
				if (value.left < 0) value.left = 0;
				if (value.top < 0) value.top = 0;
				if (value.right < 0) value.right = 0;
				if (value.bottom < 0) value.bottom = 0;

				if (extraMargin != value)
				{
					extraMargin = value;
					InvokeOnCompositionStateChanged();
				}
			}

			bool GuiStackComposition::IsStackItemClipped()
			{
				Rect clientArea = GetCachedClientArea();
				switch(direction)
				{
				case Horizontal:
				case ReversedHorizontal:
					{
						vint width = layout_stackItemTotalSize.x + extraMargin.left + extraMargin.right;
						return width > clientArea.Width();
					}
					break;
				case Vertical:
				case ReversedVertical:
					{
						vint height = layout_stackItemTotalSize.y + extraMargin.top + extraMargin.bottom;
						return height > clientArea.Height();
					}
					break;
				}
				return false;
			}

			bool GuiStackComposition::EnsureVisible(vint index)
			{
				if (0 <= index && index < layout_stackItems.Count())
				{
					layout_ensuringVisibleStackItem = layout_stackItems[index];
				}
				else
				{
					layout_ensuringVisibleStackItem = nullptr;
				}
				InvokeOnCompositionStateChanged();
				return layout_ensuringVisibleStackItem != nullptr;
			}

/***********************************************************************
GuiStackItemComposition
***********************************************************************/

			void GuiStackItemComposition::Layout_SetStackItemBounds(Rect contentBounds, Point virtualOffset)
			{
				vint x = 0;
				vint y = 0;
				switch (layout_stackParent->direction)
				{
				case GuiStackComposition::Horizontal:
					x = contentBounds.x1 + virtualOffset.x;
					y = contentBounds.y1;
					break;
				case GuiStackComposition::ReversedHorizontal:
					x = contentBounds.x2 - virtualOffset.x - cachedMinSize.x;
					y = contentBounds.y1;
					break;
				case GuiStackComposition::Vertical:
					x = contentBounds.x1;
					y = contentBounds.y1 + virtualOffset.y;
					break;
				case GuiStackComposition::ReversedVertical:
					x = contentBounds.x1;
					y = contentBounds.y2 - virtualOffset.y - cachedMinSize.y;
					break;
				}
				switch (layout_stackParent->direction)
				{
				case GuiStackComposition::Horizontal:
					x += layout_stackParent->layout_adjustment;
					break;
				case GuiStackComposition::ReversedHorizontal:
					x -= layout_stackParent->layout_adjustment;
					break;
				case GuiStackComposition::Vertical:
					y += layout_stackParent->layout_adjustment;
					break;
				case GuiStackComposition::ReversedVertical:
					y -= layout_stackParent->layout_adjustment;
					break;
				}

				vint w = 0;
				vint h = 0;
				switch (layout_stackParent->direction)
				{
				case GuiStackComposition::Horizontal:
				case GuiStackComposition::ReversedHorizontal:
					w = cachedMinSize.x;
					h = contentBounds.Height();
					break;
				case GuiStackComposition::Vertical:
				case GuiStackComposition::ReversedVertical:
					w = contentBounds.Width();
					h = cachedMinSize.y;
					break;
				}

				Rect result(
					x - extraMargin.left,
					y - extraMargin.top,
					x + w + extraMargin.right,
					y + h + extraMargin.bottom
					);
				Layout_SetCachedBounds(result);
			}

			void GuiStackItemComposition::OnParentLineChanged()
			{
				layout_stackParent = dynamic_cast<GuiStackComposition*>(GetParent());
				GuiGraphicsComposition::OnParentLineChanged();
			}

			GuiStackItemComposition::GuiStackItemComposition()
			{
				SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				CachedMinSizeChanged.AttachLambda([this](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
				{
					if (layout_stackParent) layout_stackParent->layout_invalid = true;
				});
			}

			Margin GuiStackItemComposition::GetExtraMargin()
			{
				return extraMargin;
			}

			void GuiStackItemComposition::SetExtraMargin(Margin value)
			{
				if (extraMargin != value)
				{
					extraMargin = value;
					InvokeOnCompositionStateChanged();
				}
			}
		}
	}
}


/***********************************************************************
.\GRAPHICSCOMPOSITION\GUIGRAPHICSTABLECOMPOSITION.CPP
***********************************************************************/
#include <math.h>

namespace vl
{
	namespace presentation
	{
		namespace compositions
		{
			using namespace collections;
			using namespace controls;
			using namespace elements;

/***********************************************************************
GuiTableComposition
***********************************************************************/

			namespace update_cell_bounds_helpers
			{
				vint First(vint a, vint b)
				{
					return a;
				}

				vint Second(vint a, vint b)
				{
					return b;
				}

				vint X(Size s)
				{
					return s.x;
				}

				vint Y(Size s)
				{
					return s.y;
				}

				vint RL(GuiCellComposition* cell)
				{
					return cell->GetRow();
				}

				vint CL(GuiCellComposition* cell)
				{
					return cell->GetColumn();
				}

				vint RS(GuiCellComposition* cell)
				{
					return cell->GetRowSpan();
				}

				vint CS(GuiCellComposition* cell)
				{
					return cell->GetColumnSpan();
				}
			}
			using namespace update_cell_bounds_helpers;

			Rect GuiTableComposition::Layout_CalculateCellArea(Rect tableBounds)
			{
				Rect bounds(Point(0, 0), tableBounds.GetSize());
				vint borderThickness = borderVisible ? cellPadding : 0;
				bounds.x1 += borderThickness;
				bounds.y1 += borderThickness;
				bounds.x2 -= borderThickness;
				bounds.y2 -= borderThickness;
				if (bounds.x2 < bounds.x1) bounds.x2 = bounds.x1;
				if (bounds.y2 < bounds.y1) bounds.y2 = bounds.y1;
				return bounds;
			}

			void GuiTableComposition::Layout_UpdateCellBoundsInternal(
				collections::Array<vint>& dimSizes,
				vint& dimSize,
				vint& dimSizeWithPercentage,
				collections::Array<GuiCellOption>& dimOptions,
				vint GuiTableComposition::* dim1,
				vint GuiTableComposition::* dim2,
				vint(*getSize)(Size),
				vint(*getLocation)(GuiCellComposition*),
				vint(*getSpan)(GuiCellComposition*),
				vint(*getRow)(vint, vint),
				vint(*getCol)(vint, vint)
			)
			{
				for (vint i = 0; i < this->*dim1; i++)
				{
					dimSizes[i] = 0;
				}

				for (vint i = 0; i < this->*dim1; i++)
				{
					GuiCellOption option = dimOptions[i];
					switch (option.composeType)
					{
					case GuiCellOption::Absolute:
						{
							dimSizes[i] = option.absolute;
						}
						break;
					case GuiCellOption::MinSize:
						{
							for (vint j = 0; j < this->*dim2; j++)
							{
								if (auto cell = GetSitedCell(getRow(i, j), getCol(i, j)))
								{
									if (getSpan(cell) == 1)
									{
										vint size = getSize(cell->GetCachedMinSize());
										vint span = getSpan(cell);
										for (vint k = 1; k < span; k++)
										{
											size -= dimSizes[i - k] + cellPadding;
										}
										if (dimSizes[i] < size)
										{
											dimSizes[i] = size;
										}
									}
								}
							}
						}
						break;
					default:;
					}
				}

				{
					for (vint i = 0; i < this->*dim1; i++)
					{
						GuiCellOption option = dimOptions[i];
						if (option.composeType == GuiCellOption::Percentage)
						{
							for (vint j = 0; j < this->*dim2; j++)
							{
								GuiCellComposition* cell = GetSitedCell(getRow(i, j), getCol(i, j));
								if (cell)
								{
									vint size = getSize(cell->GetCachedMinSize());
									vint start = getLocation(cell);
									vint span = getSpan(cell);
									size -= (span - 1)*cellPadding;
									double totalPercentage = 0;

									for (vint k = start; k < start + span; k++)
									{
										if (dimOptions[k].composeType == GuiCellOption::Percentage)
										{
											totalPercentage += dimOptions[k].percentage;
										}
										else
										{
											size -= dimSizes[k];
										}
									}

									size = (vint)ceil(size*option.percentage / totalPercentage);
									if (dimSizes[i] < size)
									{
										dimSizes[i] = size;
									}
								}
							}
						}
					}

					double totalPercentage = 0;
					for (vint i = 0; i < this->*dim1; i++)
					{
						GuiCellOption option = dimOptions[i];
						if (option.composeType == GuiCellOption::Percentage)
						{
							totalPercentage += option.percentage;
						}
					}

					vint percentageTotalSize = 0;
					for (vint i = 0; i < this->*dim1; i++)
					{
						GuiCellOption option = dimOptions[i];
						if (option.composeType == GuiCellOption::Percentage)
						{
							vint size = (vint)ceil(dimSizes[i] * totalPercentage / option.percentage);
							if (percentageTotalSize < size)
							{
								percentageTotalSize = size;
							}
						}
					}

					for (vint i = 0; i < this->*dim1; i++)
					{
						GuiCellOption option = dimOptions[i];
						if (option.composeType == GuiCellOption::Percentage)
						{
							vint size = (vint)ceil(percentageTotalSize * option.percentage / totalPercentage);
							if (dimSizes[i] < size)
							{
								dimSizes[i] = size;
							}
						}
					}
				}

				for (vint i = 0; i < this->*dim1; i++)
				{
					if (dimOptions[i].composeType != GuiCellOption::Percentage)
					{
						dimSize += dimSizes[i];
					}
					dimSizeWithPercentage += dimSizes[i];
				}
			}

			void GuiTableComposition::Layout_UpdateCellBoundsPercentages(
				collections::Array<vint>& dimSizes,
				vint dimSize,
				vint maxDimSize,
				collections::Array<GuiCellOption>& dimOptions
			)
			{
				if (maxDimSize > dimSize)
				{
					double totalPercentage = 0;
					vint percentageCount = 0;
					// TODO: (enumerable) foreach
					for (vint i = 0; i < dimOptions.Count(); i++)
					{
						GuiCellOption option = dimOptions[i];
						if (option.composeType == GuiCellOption::Percentage)
						{
							totalPercentage += option.percentage;
							percentageCount++;
						}
					}
					if (percentageCount > 0 && totalPercentage > 0)
					{
						// TODO: (enumerable) foreach
						for (vint i = 0; i < dimOptions.Count(); i++)
						{
							GuiCellOption option = dimOptions[i];
							if (option.composeType == GuiCellOption::Percentage)
							{
								dimSizes[i] = (vint)((maxDimSize - dimSize)*option.percentage / totalPercentage);
							}
						}
					}
				}
			}

			vint GuiTableComposition::GetSiteIndex(vint _rows, vint _columns, vint _row, vint _column)
			{
				return _row * _columns + _column;
			}

			void GuiTableComposition::SetSitedCell(vint _row, vint _column, GuiCellComposition* cell)
			{
				layout_cellCompositions[GetSiteIndex(rows, columns, _row, _column)] = cell;
				layout_invalid = true;
			}

			void GuiTableComposition::OnCompositionStateChanged()
			{
				GuiBoundsComposition::OnCompositionStateChanged();
				ConfigChanged.Execute(GuiEventArgs(this));
				layout_invalid = true;
			}

			Size GuiTableComposition::Layout_CalculateMinSize()
			{
				for (auto child : Children())
				{
					if (auto cell = dynamic_cast<GuiCellComposition*>(child))
					{
						cell->Layout_SetCachedMinSize(cell->Layout_CalculateMinSizeHelper());
					}
				}

				if (layout_invalid)
				{
					layout_invalid = false;
					layout_invalidCellBounds = true;

					layout_rowOffsets.Resize(rows);
					layout_rowSizes.Resize(rows);
					layout_columnOffsets.Resize(columns);
					layout_columnSizes.Resize(columns);
					layout_rowTotal = (rows - 1) * cellPadding;
					layout_columnTotal = (columns - 1) * cellPadding;
					layout_rowTotalWithPercentage = layout_rowTotal;
					layout_columnTotalWithPercentage = layout_columnTotal;

					Layout_UpdateCellBoundsInternal(
						layout_rowSizes,
						layout_rowTotal,
						layout_rowTotalWithPercentage,
						rowOptions,
						&GuiTableComposition::rows,
						&GuiTableComposition::columns,
						&Y,
						&RL,
						&RS,
						&First,
						&Second
					);
					Layout_UpdateCellBoundsInternal(
						layout_columnSizes,
						layout_columnTotal,
						layout_columnTotalWithPercentage,
						columnOptions,
						&GuiTableComposition::columns,
						&GuiTableComposition::rows,
						&X,
						&CL,
						&CS,
						&Second,
						&First
					);
				}

				Size minTableSize;
				if (GetMinSizeLimitation() == GuiGraphicsComposition::LimitToElementAndChildren)
				{
					vint offset = (borderVisible ? 2 * cellPadding : 0);
					minTableSize.x = layout_columnTotalWithPercentage + offset;
					minTableSize.y = layout_rowTotalWithPercentage + offset;
				}

				Size minClientSize = GuiBoundsComposition::Layout_CalculateMinSize();
				return Size(
					minTableSize.x > minClientSize.x ? minTableSize.x : minClientSize.x,
					minTableSize.y > minClientSize.y ? minTableSize.y : minClientSize.y
					);
			}

			Rect GuiTableComposition::Layout_CalculateBounds(Size parentSize)
			{
				Rect bounds = GuiBoundsComposition::Layout_CalculateBounds(parentSize);

				if (layout_lastTableSize != bounds.GetSize())
				{
					layout_invalidCellBounds = true;
					layout_lastTableSize = bounds.GetSize();
				}

				if (layout_invalidCellBounds)
				{
					layout_invalidCellBounds = false;

					Size area = Layout_CalculateCellArea(bounds).GetSize();
					Layout_UpdateCellBoundsPercentages(
						layout_rowSizes,
						layout_rowTotal,
						area.y,
						rowOptions
						);
					Layout_UpdateCellBoundsPercentages(
						layout_columnSizes,
						layout_columnTotal,
						area.x,
						columnOptions
						);

					layout_rowExtending = Layout_UpdateCellBoundsOffsets(layout_rowOffsets, layout_rowSizes, area.y);
					layout_columnExtending = Layout_UpdateCellBoundsOffsets(layout_columnOffsets, layout_columnSizes, area.x);

					for (vint i = 0; i < rows; i++)
					{
						for (vint j = 0; j < columns; j++)
						{
							vint index = GetSiteIndex(rows, columns, i, j);
							layout_cellBounds[index] = Rect(Point(layout_columnOffsets[j], layout_rowOffsets[i]), Size(layout_columnSizes[j], layout_rowSizes[i]));
						}
					}

					for (auto child : Children())
					{
						if (auto cell = dynamic_cast<GuiCellComposition*>(child))
						{
							cell->Layout_SetCellBounds();
						}
					}
				}

				return bounds;
			}

			vint GuiTableComposition::Layout_UpdateCellBoundsOffsets(
				collections::Array<vint>& offsets,
				collections::Array<vint>& sizes,
				vint max
				)
			{
				offsets[0] = 0;
				for (vint i = 1; i < offsets.Count(); i++)
				{
					offsets[i] = offsets[i - 1] + cellPadding + sizes[i - 1];
				}

				vint last = offsets.Count() - 1;
				vint right = offsets[last] + sizes[last];
				return max > right ? max - right : 0;
			}

			GuiTableComposition::GuiTableComposition()
			{
				ConfigChanged.SetAssociatedComposition(this);
				SetRowsAndColumns(1, 1);
			}

			vint GuiTableComposition::GetRows()
			{
				return rows;
			}

			vint GuiTableComposition::GetColumns()
			{
				return columns;
			}

			bool GuiTableComposition::SetRowsAndColumns(vint _rows, vint _columns)
			{
				if (_rows <= 0 || _columns <= 0) return false;
				rowOptions.Resize(_rows);
				columnOptions.Resize(_columns);
				layout_cellCompositions.Resize(_rows*_columns);
				layout_cellBounds.Resize(_rows*_columns);
				for (vint i = 0; i < _rows*_columns; i++)
				{
					layout_cellCompositions[i] = nullptr;
					layout_cellBounds[i] = Rect();
				}
				rows = _rows;
				columns = _columns;
				// TODO: (enumerable) foreach
				vint childCount = Children().Count();
				for (vint i = 0; i < childCount; i++)
				{
					GuiCellComposition* cell = dynamic_cast<GuiCellComposition*>(Children().Get(i));
					if (cell)
					{
						cell->OnTableRowsAndColumnsChanged();
					}
				}
				InvokeOnCompositionStateChanged();
				return true;
			}

			GuiCellComposition* GuiTableComposition::GetSitedCell(vint _row, vint _column)
			{
				return layout_cellCompositions[GetSiteIndex(rows, columns, _row, _column)];
			}

			GuiCellOption GuiTableComposition::GetRowOption(vint _row)
			{
				return rowOptions[_row];
			}

			void GuiTableComposition::SetRowOption(vint _row, GuiCellOption option)
			{
				if (option.composeType == GuiCellOption::Percentage && option.percentage < 0.001)
				{
					option.percentage = 0;
				}

				if (rowOptions[_row] != option)
				{
					rowOptions[_row] = option;
					InvokeOnCompositionStateChanged();
				}
			}

			GuiCellOption GuiTableComposition::GetColumnOption(vint _column)
			{
				return columnOptions[_column];
			}

			void GuiTableComposition::SetColumnOption(vint _column, GuiCellOption option)
			{
				if (option.composeType == GuiCellOption::Percentage && option.percentage < 0.001)
				{
					option.percentage = 0;
				}

				if (columnOptions[_column] != option)
				{
					columnOptions[_column] = option;
					InvokeOnCompositionStateChanged();
				}
			}

			vint GuiTableComposition::GetCellPadding()
			{
				return cellPadding;
			}

			void GuiTableComposition::SetCellPadding(vint value)
			{
				if (value < 0) value = 0;
				if (cellPadding != value)
				{
					cellPadding = value;
					InvokeOnCompositionStateChanged();
				}
			}

			bool GuiTableComposition::GetBorderVisible()
			{
				return borderVisible;
			}

			void GuiTableComposition::SetBorderVisible(bool value)
			{
				if (borderVisible != value)
				{
					borderVisible = value;
					InvokeOnCompositionStateChanged();
				}
			}

/***********************************************************************
GuiCellComposition
***********************************************************************/

			void GuiCellComposition::ClearSitedCells(GuiTableComposition* table)
			{
				if (row != -1 && column != -1)
				{
					for (vint r = 0; r < rowSpan; r++)
					{
						for (vint c = 0; c < columnSpan; c++)
						{
							table->SetSitedCell(row + r, column + c, nullptr);
						}
					}
				}
			}

			void GuiCellComposition::SetSitedCells(GuiTableComposition* table)
			{
				for (vint r = 0; r < rowSpan; r++)
				{
					for (vint c = 0; c < columnSpan; c++)
					{
						table->SetSitedCell(row + r, column + c, this);
					}
				}
			}

			void GuiCellComposition::ResetSiteInternal()
			{
				row = -1;
				column = -1;
				rowSpan = 1;
				columnSpan = 1;
			}

			bool GuiCellComposition::SetSiteInternal(vint _row, vint _column, vint _rowSpan, vint _columnSpan)
			{
				if (layout_tableParent)
				{
					if (_row < 0 || _row >= layout_tableParent->rows || _column < 0 || _column >= layout_tableParent->columns) return false;
					if (_rowSpan<1 || _row + _rowSpan>layout_tableParent->rows || _columnSpan<1 || _column + _columnSpan>layout_tableParent->columns) return false;

					for (vint r = 0; r < _rowSpan; r++)
					{
						for (vint c = 0; c < _columnSpan; c++)
						{
							GuiCellComposition* cell = layout_tableParent->GetSitedCell(_row + r, _column + c);
							if (cell && cell != this)
							{
								return false;
							}
						}
					}
					ClearSitedCells(layout_tableParent);
				}

				row = _row;
				column = _column;
				rowSpan = _rowSpan;
				columnSpan = _columnSpan;

				if (layout_tableParent)
				{
					SetSitedCells(layout_tableParent);
				}
				return true;
			}

			void GuiCellComposition::OnParentChanged(GuiGraphicsComposition* oldParent, GuiGraphicsComposition* newParent)
			{
				GuiGraphicsComposition::OnParentChanged(oldParent, newParent);
				if (layout_tableParent)
				{
					ClearSitedCells(layout_tableParent);
				}
				layout_tableParent = dynamic_cast<GuiTableComposition*>(newParent);
				if (!layout_tableParent || !SetSiteInternal(row, column, rowSpan, columnSpan))
				{
					ResetSiteInternal();
				}
				if (layout_tableParent)
				{
					if (row != -1 && column != -1)
					{
						SetSiteInternal(row, column, rowSpan, columnSpan);
					}
				}
			}

			void GuiCellComposition::OnTableRowsAndColumnsChanged()
			{
				if(!SetSiteInternal(row, column, rowSpan, columnSpan))
				{
					ResetSiteInternal();
				}
			}

			void GuiCellComposition::Layout_SetCellBounds()
			{
				Rect result;
				if (layout_tableParent && row != -1 && column != -1)
				{
					Rect bounds1, bounds2;
					{
						vint index = layout_tableParent->GetSiteIndex(layout_tableParent->rows, layout_tableParent->columns, row, column);
						bounds1 = layout_tableParent->layout_cellBounds[index];
					}
					{
						vint index = layout_tableParent->GetSiteIndex(layout_tableParent->rows, layout_tableParent->columns, row + rowSpan - 1, column + columnSpan - 1);
						bounds2 = layout_tableParent->layout_cellBounds[index];

						if (row + rowSpan == layout_tableParent->rows)
						{
							bounds2.y2 += layout_tableParent->layout_rowExtending;
						}
						if (column + columnSpan == layout_tableParent->columns)
						{
							bounds2.x2 += layout_tableParent->layout_columnExtending;
						}
					}
					vint offset = layout_tableParent->borderVisible ? layout_tableParent->cellPadding : 0;
					result = Rect(bounds1.x1 + offset, bounds1.y1 + offset, bounds2.x2 + offset, bounds2.y2 + offset);
				}
				else
				{
					result = Rect();
				}
				Layout_SetCachedBounds(result);
			}

			GuiCellComposition::GuiCellComposition()
			{
				SetMinSizeLimitation(GuiGraphicsComposition::LimitToElementAndChildren);
				CachedMinSizeChanged.AttachLambda([this](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
				{
					if (layout_tableParent) layout_tableParent->layout_invalid = true;
				});
			}

			GuiTableComposition* GuiCellComposition::GetTableParent()
			{
				return layout_tableParent;
			}

			vint GuiCellComposition::GetRow()
			{
				return row;
			}

			vint GuiCellComposition::GetRowSpan()
			{
				return rowSpan;
			}

			vint GuiCellComposition::GetColumn()
			{
				return column;
			}

			vint GuiCellComposition::GetColumnSpan()
			{
				return columnSpan;
			}

			bool GuiCellComposition::SetSite(vint _row, vint _column, vint _rowSpan, vint _columnSpan)
			{
				if (!SetSiteInternal(_row, _column, _rowSpan, _columnSpan))
				{
					return false;
				}

				InvokeOnCompositionStateChanged();
				return true;
			}

/***********************************************************************
GuiTableSplitterCompositionBase
***********************************************************************/

			void GuiTableSplitterCompositionBase::OnParentChanged(GuiGraphicsComposition* oldParent, GuiGraphicsComposition* newParent)
			{
				GuiGraphicsComposition::OnParentChanged(oldParent, newParent);
				tableParent = dynamic_cast<GuiTableComposition*>(newParent);
			}

			void GuiTableSplitterCompositionBase::OnLeftButtonDown(GuiGraphicsComposition* sender, GuiMouseEventArgs& arguments)
			{
				dragging = true;
				draggingPoint = Point(arguments.x, arguments.y);
			}

			void GuiTableSplitterCompositionBase::OnLeftButtonUp(GuiGraphicsComposition* sender, GuiMouseEventArgs& arguments)
			{
				dragging = false;
			}

			void GuiTableSplitterCompositionBase::OnMouseMoveHelper(
				vint cellsBefore,
				vint GuiTableComposition::* cells,
				collections::Array<vint>& cellSizes,
				vint offset,
				GuiCellOption(GuiTableComposition::*getOption)(vint),
				void(GuiTableComposition::*setOption)(vint, GuiCellOption)
				)
			{
				if (dragging)
				{
					if (tableParent)
					{
						if (0 < cellsBefore && cellsBefore < tableParent->*cells)
						{
							auto o1 = (tableParent->*getOption)(cellsBefore - 1);
							auto o2 = (tableParent->*getOption)(cellsBefore);

							vint indexStart = -1;
							vint indexEnd = -1;
							vint indexStep = -1;
							vint max = 0;

							if (offset < 0)
							{
								indexStart = cellsBefore - 1;
								indexEnd = -1;
								indexStep = -1;
							}
							else if (offset > 0)
							{
								indexStart = cellsBefore;
								indexEnd = tableParent->*cells;
								indexStep = 1;
							}
							else
							{
								return;
							}

							{
								auto o = (tableParent->*getOption)(indexStart);
								if (o.composeType == GuiCellOption::Absolute)
								{
									max = o.absolute - 1;
								}
								else
								{
									for (vint i = indexStart; i != indexEnd; i += indexStep)
									{
										o = (tableParent->*getOption)(i);
										if (o.composeType == GuiCellOption::Absolute)
										{
											break;
										}
										else if (o.composeType == GuiCellOption::Percentage)
										{
											max += cellSizes[i] - 1;
										}
									}
								}

								if (max <= 0)
								{
									return;
								}
							}

							if (offset < 0)
							{
								if (max < -offset)
								{
									offset = -max;
								}
							}
							else
							{
								if (max < offset)
								{
									offset = max;
								}
							}

							if (o1.composeType == GuiCellOption::Absolute)
							{
								o1.absolute += offset;
								(tableParent->*setOption)(cellsBefore - 1, o1);
							}
							if (o2.composeType == GuiCellOption::Absolute)
							{
								o2.absolute -= offset;
								(tableParent->*setOption)(cellsBefore, o2);
							}
							tableParent->ForceCalculateSizeImmediately();
						}
					}
				}
			}

			Rect GuiTableSplitterCompositionBase::GetBoundsHelper(
				vint cellsBefore,
				vint GuiTableComposition::* cells,
				vint(Rect::* dimSize)()const,
				collections::Array<vint>& cellOffsets,
				vint Rect::* dimU1,
				vint Rect::* dimU2,
				vint Rect::* dimV1,
				vint Rect::* dimV2
				)
			{
				Rect result;
				if (tableParent)
				{
					if (0 < cellsBefore && cellsBefore < tableParent->*cells)
					{
						vint offset = tableParent->borderVisible ? tableParent->cellPadding : 0;
						result.*dimU1 = offset;
						result.*dimU2 = offset + (tableParent->Layout_CalculateCellArea(tableParent->GetCachedBounds()).*dimSize)();
						result.*dimV1 = offset + cellOffsets[cellsBefore] - tableParent->cellPadding;
						result.*dimV2 = (result.*dimV1) + tableParent->cellPadding;
					}
				}
				return result;
			}
			
			GuiTableSplitterCompositionBase::GuiTableSplitterCompositionBase()
			{
				GetEventReceiver()->leftButtonDown.AttachMethod(this, &GuiTableSplitterCompositionBase::OnLeftButtonDown);
				GetEventReceiver()->leftButtonUp.AttachMethod(this, &GuiTableSplitterCompositionBase::OnLeftButtonUp);
			}

			GuiTableComposition* GuiTableSplitterCompositionBase::GetTableParent()
			{
				return tableParent;
			}

/***********************************************************************
GuiRowSplitterComposition
***********************************************************************/

			void GuiRowSplitterComposition::OnMouseMove(GuiGraphicsComposition* sender, GuiMouseEventArgs& arguments)
			{
				OnMouseMoveHelper(
					rowsToTheTop,
					&GuiTableComposition::rows,
					tableParent->layout_rowSizes,
					arguments.y - draggingPoint.y,
					&GuiTableComposition::GetRowOption,
					&GuiTableComposition::SetRowOption
					);
			}

			Rect GuiRowSplitterComposition::Layout_CalculateBounds(Size parentSize)
			{
				return GetBoundsHelper(
					rowsToTheTop,
					&GuiTableComposition::rows,
					&Rect::Width,
					tableParent->layout_rowOffsets,
					&Rect::x1,
					&Rect::x2,
					&Rect::y1,
					&Rect::y2
					);
			}
			
			GuiRowSplitterComposition::GuiRowSplitterComposition()
			{
				if (auto controller = GetCurrentController())
				{
					SetAssociatedCursor(controller->ResourceService()->GetSystemCursor(INativeCursor::SizeNS));
				}
				GetEventReceiver()->mouseMove.AttachMethod(this, &GuiRowSplitterComposition::OnMouseMove);
			}

			vint GuiRowSplitterComposition::GetRowsToTheTop()
			{
				return rowsToTheTop;
			}

			void GuiRowSplitterComposition::SetRowsToTheTop(vint value)
			{
				if (rowsToTheTop != value)
				{
					rowsToTheTop = value;
					InvokeOnCompositionStateChanged();
				}
			}

/***********************************************************************
GuiColumnSplitterComposition
***********************************************************************/

			void GuiColumnSplitterComposition::OnMouseMove(GuiGraphicsComposition* sender, GuiMouseEventArgs& arguments)
			{
				OnMouseMoveHelper(
					columnsToTheLeft,
					&GuiTableComposition::columns,
					tableParent->layout_columnSizes,
					arguments.x - draggingPoint.x,
					&GuiTableComposition::GetColumnOption,
					&GuiTableComposition::SetColumnOption
					);
			}

			Rect GuiColumnSplitterComposition::Layout_CalculateBounds(Size parentSize)
			{
				return GetBoundsHelper(
					columnsToTheLeft,
					&GuiTableComposition::columns,
					&Rect::Height,
					tableParent->layout_columnOffsets,
					&Rect::y1,
					&Rect::y2,
					&Rect::x1,
					&Rect::x2
					);
			}
			
			GuiColumnSplitterComposition::GuiColumnSplitterComposition()
			{
				if (auto controller = GetCurrentController())
				{
					SetAssociatedCursor(controller->ResourceService()->GetSystemCursor(INativeCursor::SizeWE));
				}
				GetEventReceiver()->mouseMove.AttachMethod(this, &GuiColumnSplitterComposition::OnMouseMove);
			}

			vint GuiColumnSplitterComposition::GetColumnsToTheLeft()
			{
				return columnsToTheLeft;
			}

			void GuiColumnSplitterComposition::SetColumnsToTheLeft(vint value)
			{
				if (columnsToTheLeft != value)
				{
					columnsToTheLeft = value;
					InvokeOnCompositionStateChanged();
				}
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSELEMENT\GUIGRAPHICSDOCUMENTELEMENT.CPP
***********************************************************************/

namespace vl
{
	using namespace collections;

	namespace presentation
	{
		namespace elements
		{

/***********************************************************************
GuiDocumentElement
***********************************************************************/

			Ptr<IGuiDocumentElementRenderer> GuiDocumentElement::GetElementRenderer()
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::GetElementRenderer()#"
				if (!renderer) return nullptr;
				auto elementRenderer = renderer.Cast<IGuiDocumentElementRenderer>();
				CHECK_ERROR(elementRenderer, ERROR_MESSAGE_PREFIX L"The registered renderer for GuiDocumentElement must implement IGuiDocumentElementRenderer.");
				return elementRenderer;
#undef ERROR_MESSAGE_PREFIX
			}

			void GuiDocumentElement::UpdateCaret()
			{
				if (auto elementRenderer = GetElementRenderer())
				{
					elementRenderer->SetSelection(caretBegin, caretEnd);
					if (caretVisible)
					{
						elementRenderer->EnableCaret(caretEnd, caretColor, caretFrontSide);
					}
					else
					{
						elementRenderer->DisableCaret();
					}
					InvokeOnCompositionStateChanged();
				}
			}

			GuiDocumentElement::GuiDocumentElement()
				:passwordChar(0)
				,caretVisible(false)
				,caretFrontSide(false)
			{
			}

			IGuiDocumentElementCallback* GuiDocumentElement::GetCallback()
			{
				return callback;
			}

			void GuiDocumentElement::SetCallback(IGuiDocumentElementCallback* value)
			{
				callback = value;
			}

			Ptr<DocumentModel> GuiDocumentElement::GetDocument()
			{
				return document;
			}

			void GuiDocumentElement::SetDocument(Ptr<DocumentModel> value)
			{
				if (document != value)
				{
					document = value;
					InvokeOnElementStateChanged();
					SetCaret(TextPos(), TextPos(), false);
				}
			}

			bool GuiDocumentElement::GetParagraphPadding()
			{
				return paragraphPadding;
			}

			void GuiDocumentElement::SetParagraphPadding(bool value)
			{
				if (paragraphPadding != value)
				{
					paragraphPadding = value;
					if (auto elementRenderer = GetElementRenderer())
					{
						elementRenderer->NotifyParagraphPaddingUpdated(paragraphPadding);
						InvokeOnCompositionStateChanged();
					}
				}
			}

			bool GuiDocumentElement::GetWrapLine()
			{
				return wrapLine;
			}

			void GuiDocumentElement::SetWrapLine(bool value)
			{
				if (wrapLine != value)
				{
					wrapLine = value;
					InvokeOnElementStateChanged();
				}
			}

			wchar_t GuiDocumentElement::GetPasswordChar()
			{
				return passwordChar;
			}

			void GuiDocumentElement::SetPasswordChar(wchar_t value)
			{
				if (passwordChar != value)
				{
					passwordChar = value;
					InvokeOnElementStateChanged();
				}
			}

			bool GuiDocumentElement::GetParagraphRecycle()
			{
				return paragraphRecycle;
			}

			void GuiDocumentElement::SetParagraphRecycle(bool value)
			{
				paragraphRecycle = value;
			}

			TextPos GuiDocumentElement::GetCaretBegin()
			{
				return caretBegin;
			}

			TextPos GuiDocumentElement::GetCaretEnd()
			{
				return caretEnd;
			}

			bool GuiDocumentElement::IsCaretEndPreferFrontSide()
			{
				return caretFrontSide;
			}

			void GuiDocumentElement::SetCaret(TextPos begin, TextPos end, bool frontSide)
			{
				caretBegin=begin;
				caretEnd=end;
				if(caretBegin<caretEnd)
				{
					caretFrontSide=true;
				}
				else if(caretBegin>caretEnd)
				{
					caretFrontSide=false;
				}
				else
				{
					caretFrontSide=frontSide;
				}
				UpdateCaret();
			}

			bool GuiDocumentElement::GetCaretVisible()
			{
				return caretVisible;
			}

			void GuiDocumentElement::SetCaretVisible(bool value)
			{
				caretVisible=value;
				UpdateCaret();
			}

			void GuiDocumentElement::BlinkCaret()
			{
				if (auto elementRenderer = GetElementRenderer())
				{
					if (elementRenderer->BlinkCaret())
					{
						InvokeOnCompositionStateChanged();
					}
				}
			}

			Color GuiDocumentElement::GetCaretColor()
			{
				return caretColor;
			}

			void GuiDocumentElement::SetCaretColor(Color value)
			{
				caretColor=value;
				UpdateCaret();
			}

			TextPos GuiDocumentElement::CalculateCaret(TextPos comparingCaret, IGuiGraphicsParagraph::CaretRelativePosition position, bool& preferFrontSide)
			{
				if (auto elementRenderer = GetElementRenderer())
				{
					TextPos caret = elementRenderer->CalculateCaret(comparingCaret, position, preferFrontSide);
					return caret.column == -1 ? comparingCaret : caret;
				}
				return {};
			}

			TextPos GuiDocumentElement::CalculateCaretFromPoint(Point point)
			{
				if (auto elementRenderer = GetElementRenderer())
				{
					return elementRenderer->CalculateCaretFromPoint(point);
				}
				return {};
			}

			Rect GuiDocumentElement::GetCaretBounds(TextPos caret, bool frontSide)
			{
				if (auto elementRenderer = GetElementRenderer())
				{
					return elementRenderer->GetCaretBounds(caret, frontSide);
				}
				return {};
			}
			
			void GuiDocumentElement::NotifyParagraphUpdated(vint index, vint oldCount, vint newCount, bool updatedText)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::GuiDocumentElement::NotifyParagraphUpdated(vint, vint, vint, bool)#"
				if (auto elementRenderer = GetElementRenderer())
				{
					if (updatedText)
					{
						elementRenderer->NotifyParagraphTextUpdated(index, oldCount, newCount);
					}
					else
					{
						CHECK_ERROR(oldCount == newCount, ERROR_MESSAGE_PREFIX L"updatedText must be true if oldCount is not equal to newCount");
						elementRenderer->NotifyParagraphStyleUpdated(index, oldCount);
					}
					InvokeOnCompositionStateChanged();
				}
#undef ERROR_MESSAGE_PREFIX
			}

			void GuiDocumentElement::EditRun(TextPos begin, TextPos end, Ptr<DocumentModel> model, bool copy)
			{
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				vint newRows = document->EditRun(begin, end, model, copy);
				if (newRows != -1)
				{
					if (auto elementRenderer = GetElementRenderer())
					{
						elementRenderer->NotifyParagraphTextUpdated(begin.row, end.row - begin.row + 1, newRows);
						InvokeOnCompositionStateChanged();
					}
				}
			}

			void GuiDocumentElement::EditText(TextPos begin, TextPos end, bool frontSide, const collections::Array<WString>& text)
			{
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				vint newRows = document->EditText(begin, end, frontSide, text);
				if (newRows != -1)
				{
					if (auto elementRenderer = GetElementRenderer())
					{
						elementRenderer->NotifyParagraphTextUpdated(begin.row, end.row - begin.row + 1, newRows);
						InvokeOnCompositionStateChanged();
					}
				}
			}

			void GuiDocumentElement::EditStyle(TextPos begin, TextPos end, Ptr<DocumentStyleProperties> style)
			{
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				if (document->EditStyle(begin, end, style))
				{
					if (auto elementRenderer = GetElementRenderer())
					{
						elementRenderer->NotifyParagraphStyleUpdated(begin, end);
						InvokeOnCompositionStateChanged();
					}
				}
			}

			void GuiDocumentElement::EditImage(TextPos begin, TextPos end, Ptr<GuiImageData> image)
			{
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				if (document->EditImage(begin, end, image))
				{
					if (auto elementRenderer = GetElementRenderer())
					{
						elementRenderer->NotifyParagraphTextUpdated(begin.row, end.row - begin.row + 1, 1);
						InvokeOnCompositionStateChanged();
					}
				}
			}

			void GuiDocumentElement::EditHyperlink(vint paragraphIndex, vint begin, vint end, const WString& reference, const WString& normalStyleName, const WString& activeStyleName)
			{
				if (begin > end)
				{
					vint temp = begin;
					begin = end;
					end = temp;
				}

				if (document->EditHyperlink(paragraphIndex, begin, end, reference, normalStyleName, activeStyleName))
				{
					if (auto elementRenderer = GetElementRenderer())
					{
						elementRenderer->NotifyParagraphStyleUpdated({ paragraphIndex, begin }, { paragraphIndex,end });
						InvokeOnCompositionStateChanged();
					}
				}
			}

			void GuiDocumentElement::RemoveHyperlink(vint paragraphIndex, vint begin, vint end)
			{
				if (begin > end)
				{
					vint temp = begin;
					begin = end;
					end = temp;
				}

				if (document->RemoveHyperlink(paragraphIndex, begin, end))
				{
					if (auto elementRenderer = GetElementRenderer())
					{
						elementRenderer->NotifyParagraphStyleUpdated({ paragraphIndex, begin }, { paragraphIndex,end });
						InvokeOnCompositionStateChanged();
					}
				}
			}

			void GuiDocumentElement::EditStyleName(TextPos begin, TextPos end, const WString& styleName)
			{
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				if (document->EditStyleName(begin, end, styleName))
				{
					if (auto elementRenderer = GetElementRenderer())
					{
						elementRenderer->NotifyParagraphStyleUpdated(begin, end);
						InvokeOnCompositionStateChanged();
					}
				}
			}

			void GuiDocumentElement::RemoveStyleName(TextPos begin, TextPos end)
			{
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				if (document->RemoveStyleName(begin, end))
				{
					if (auto elementRenderer = GetElementRenderer())
					{
						elementRenderer->NotifyParagraphStyleUpdated(begin, end);
						InvokeOnCompositionStateChanged();
					}
				}
			}

			void GuiDocumentElement::RenameStyle(const WString& oldStyleName, const WString& newStyleName)
			{
				document->RenameStyle(oldStyleName, newStyleName);
			}

			void GuiDocumentElement::ClearStyle(TextPos begin, TextPos end)
			{
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				if (document->ClearStyle(begin, end))
				{
					if (auto elementRenderer = GetElementRenderer())
					{
						elementRenderer->NotifyParagraphStyleUpdated(begin, end);
						InvokeOnCompositionStateChanged();
					}
				}
			}

			void GuiDocumentElement::ConvertToPlainText(TextPos begin, TextPos end)
			{
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				if (document->ConvertToPlainText(begin, end))
				{
					if (auto elementRenderer = GetElementRenderer())
					{
						elementRenderer->NotifyParagraphStyleUpdated(begin, end);
						InvokeOnCompositionStateChanged();
					}
				}
			}

			Ptr<DocumentStyleProperties> GuiDocumentElement::SummarizeStyle(TextPos begin, TextPos end)
			{
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				return document->SummarizeStyle(begin, end);
			}

			Nullable<WString> GuiDocumentElement::SummarizeStyleName(TextPos begin, TextPos end)
			{
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				return document->SummarizeStyleName(begin, end);
			}

			void GuiDocumentElement::SetParagraphAlignment(TextPos begin, TextPos end, const collections::Array<Nullable<Alignment>>& alignments)
			{
				vint first = begin.row;
				vint last = end.row;
				if (first > last)
				{
					vint temp = first;
					first = last;
					last = temp;
				}

				if (0 <= first && first < document->paragraphs.Count() && 0 <= last && last < document->paragraphs.Count() && last - first + 1 == alignments.Count())
				{
					for (vint i = first; i <= last; i++)
					{
						document->paragraphs[i]->alignment = alignments[i - first];
					}
					if (auto elementRenderer = GetElementRenderer())
					{
						for (vint i = first; i <= last; i++)
						{
							elementRenderer->NotifyParagraphStyleUpdated({ i,0 }, { i,0 });
						}
						InvokeOnCompositionStateChanged();
					}
				}
			}

			Nullable<Alignment> GuiDocumentElement::SummarizeParagraphAlignment(TextPos begin, TextPos end)
			{
				if (begin > end)
				{
					TextPos temp = begin;
					begin = end;
					end = temp;
				}

				return document->SummarizeParagraphAlignment(begin, end);
			}

			Ptr<DocumentHyperlinkRun::Package> GuiDocumentElement::GetHyperlinkFromPoint(Point point)
			{
				if (auto elementRenderer = GetElementRenderer())
				{
					return elementRenderer->GetHyperlinkFromPoint(point);
				}
				return {};
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSELEMENT\GUIGRAPHICSDOCUMENTRENDERER_GUIDOCUMENTELEMENTRENDERER.CPP
***********************************************************************/

namespace vl
{
	using namespace collections;

	namespace presentation
	{
		namespace elements
		{

/***********************************************************************
GuiDocumentElementRenderer
***********************************************************************/

			Size GuiDocumentElementRenderer::OnRenderInlineObject(vint callbackId, Rect location)
			{
				if (auto callback = element->GetCallback())
				{
					auto cache = pgCache.GetParagraphCache(renderingParagraph, true);
					auto relativeLocation = Rect(Point(location.x1 + renderingParagraphOffset.x, location.y1 + renderingParagraphOffset.y), location.GetSize());
					auto eo = cache->embeddedObjects[callbackId];
					auto size = callback->OnRenderEmbeddedObject(eo->name, relativeLocation);
					eo->resized = eo->size != size;
					eo->size = size;
					return eo->size;
				}
				else
				{
					return Size();
				}
			}

			void GuiDocumentElementRenderer::InitializeInternal()
			{
				pgCache.Initialize(element);
				imageCache.Initialize(element);
				NotifyParagraphPaddingUpdated(element->GetParagraphPadding());
			}

			void GuiDocumentElementRenderer::FinalizeInternal()
			{
			}

			void GuiDocumentElementRenderer::RenderTargetChangedInternal(IGuiGraphicsRenderTarget* oldRenderTarget, IGuiGraphicsRenderTarget* newRenderTarget)
			{
				pgCache.RenderTargetChanged(oldRenderTarget, newRenderTarget);
				imageCache.RenderTargetChanged(oldRenderTarget, newRenderTarget);
			}

			Ptr<pg::ParagraphCache> GuiDocumentElementRenderer::EnsureParagraph(vint paragraphIndex)
			{
				auto cache = pgCache.TryGetParagraphCache(paragraphIndex);
				bool paragraphAlreadyCreated = cache && cache->graphicsParagraph;

				lastTotalHeightWithoutParagraphDistance += pgCache.EnsureParagraph(paragraphIndex, lastMaxWidth);
				vint width = pgCache.GetParagraphSize(paragraphIndex).x;
				if (lastTotalWidth < width)
				{
					lastTotalWidth = width;
				}
				FixMinSize();
				cache = pgCache.GetParagraphCache(paragraphIndex, true);

				if (!paragraphAlreadyCreated && paragraphIndex == lastCaret.row && element->GetCaretVisible())
				{
					cache->graphicsParagraph->EnableCaret(lastCaret.column, lastCaretColor, lastCaretFrontSide);
				}
				return cache;
			}

			void GuiDocumentElementRenderer::FixMinSize()
			{
				minSize = { lastTotalWidth,lastTotalHeightWithoutParagraphDistance };
				if (pgCache.GetParagraphCount() > 0)
				{
					minSize.y += paragraphDistance * (pgCache.GetParagraphCount() - 1);
				}

				if (minSize.x < 1) minSize.x = 1;
				if (minSize.y < 1) minSize.y = 1;
			}

			void GuiDocumentElementRenderer::UpdateRenderRange(vint index, vint oldCount, vint newCount)
			{
				// Range adjustment logic for paragraph recycling
				if (previousRenderBegin != -1)
				{
					// Handle the three cases for range adjustment when text is actually updated
					vint prevEnd = previousRenderBegin + previousRenderCount;
					vint oldEnd = index + oldCount;
					
					if (previousRenderBegin + previousRenderCount <= index)
					{
						// Case 1: Previous range is completely before the updated area - no adjustment needed
					}
					else if (previousRenderBegin >= oldEnd)
					{
						// Case 2: Previous range is completely after the updated area - adjust begin position
						previousRenderBegin += (newCount - oldCount);
					}
					else
					{
						// Case 3: Previous range overlaps with updated area - use union approach
						vint newBegin = previousRenderBegin < index ? previousRenderBegin : index;
						vint unionEnd = prevEnd > oldEnd ? prevEnd : oldEnd;
						vint newCountAdjustment = unionEnd - newBegin + (newCount - oldCount);
						
						previousRenderBegin = newBegin;
						previousRenderCount = newCountAdjustment;
					}
					
					// Reset to invalid state when count becomes 0 (per UPDATE guidance)
					if (previousRenderCount <= 0)
					{
						previousRenderBegin = -1;
						previousRenderCount = 0;
					}
				}
			}

			void GuiDocumentElementRenderer::UpdateRenderRangeAndCleanUp(vint currentBegin, vint currentCount)
			{
				// Apply recycling logic if we have valid previous range
				if (previousRenderBegin != -1 && element->GetParagraphRecycle())
				{
					if (currentBegin == -1)
					{
						// Release everything when no paragraphs are currently visible
						pgCache.ReleaseParagraphs(previousRenderBegin, previousRenderCount);
					}
					else
					{
						vint prevEnd = previousRenderBegin + previousRenderCount;
						vint currEnd = currentBegin + currentCount;
						
						// Release paragraphs before current range
						if (previousRenderBegin < currentBegin)
						{
							vint releaseEnd = prevEnd < currentBegin ? prevEnd : currentBegin;
							pgCache.ReleaseParagraphs(previousRenderBegin, releaseEnd - previousRenderBegin);
						}
						
						// Release paragraphs after current range
						if (prevEnd > currEnd)
						{
							vint releaseBegin = currEnd > previousRenderBegin ? currEnd : previousRenderBegin;
							pgCache.ReleaseParagraphs(releaseBegin, prevEnd - releaseBegin);
						}
					}
				}
				
				// Update tracking variables for next render cycle
				previousRenderBegin = currentBegin;
				previousRenderCount = currentCount;
				
				// Reset to invalid state when no paragraphs are visible (per UPDATE guidance)
				if (previousRenderCount == 0)
				{
					previousRenderBegin = -1;
				}
			}

			void GuiDocumentElementRenderer::ApplyPropertiesOnParagraph(vint paragraphIndex, vint start, vint end, vint maxWidth)
			{
				auto cache = pgCache.GetParagraphCache(paragraphIndex, true);
				auto paragraph = element->GetDocument()->paragraphs[paragraphIndex];
				visitors::SetProperties(
					element->GetDocument().Obj(),
					&pgCache,
					&imageCache,
					cache,
					paragraphIndex,
					paragraph,
					cache->selectionBegin,
					cache->selectionEnd,
					start,
					end
				);
				cache->graphicsParagraph->SetParagraphAlignment(paragraph->alignment ? paragraph->alignment.Value() : Alignment::Left);
				cache->graphicsParagraph->SetWrapLine(element->GetWrapLine());
				cache->graphicsParagraph->SetMaxWidth(maxWidth);
			}

			GuiDocumentElementRenderer::GuiDocumentElementRenderer()
				: pgCache(this)
			{
			}

			GuiDocumentElementRenderer::~GuiDocumentElementRenderer()
			{
			}

			void GuiDocumentElementRenderer::Render(Rect bounds)
			{
				List<vint> paragraphsToReset;
				if (auto callback = element->GetCallback())
				{
					callback->OnStartRender();
				}
				renderTarget->PushClipper(bounds, element);
				if (!renderTarget->IsClipperCoverWholeTarget())
				{
					vint maxWidth = bounds.Width();
					Rect clipper = renderTarget->GetClipper();
					vint cx = bounds.Left();
					vint cy = bounds.Top();
					vint y1 = clipper.Top() - bounds.Top();
					vint y2 = y1 + clipper.Height();

					lastMaxWidth = maxWidth;

					// TODO: (enumerable) foreach
					vint paragraphCount = pgCache.GetParagraphCount();
					auto document = element->GetDocument();
					if (paragraphCount > document->paragraphs.Count())
					{
						paragraphCount = document->paragraphs.Count();
					}

					vint startParagraph = pgCache.GetParagraphFromY(y1, paragraphDistance);
					for (vint i = startParagraph; i < paragraphCount; i++)
					{
						Ptr<DocumentParagraphRun> paragraph = document->paragraphs[i];
						auto cache = EnsureParagraph(i);

						vint y = pgCache.GetParagraphTop(i, paragraphDistance);
						if (y >= y2)
						{
							break;
						}

						renderingParagraph = i;
						renderingParagraphOffset = Point(cx - bounds.x1, cy + y - bounds.y1);
						cache->graphicsParagraph->Render(Rect(Point(cx, cy + y), Size(maxWidth, pgCache.GetParagraphSize(i).y)));
						renderingParagraph = -1;

						bool resized = false;
						for (auto eo : cache->embeddedObjects.Values())
						{
							if (eo->resized)
							{
								eo->resized = false;
								resized = true;
							}
						}

						if (resized)
						{
							paragraphsToReset.Add(i);
						}
					}
				}
				renderTarget->PopClipper(element);
				if (auto callback = element->GetCallback())
				{
					callback->OnFinishRender();
				}

				// Paragraph recycling logic
				if (element->GetParagraphRecycle())
				{
					// Calculate current visible range (currentBegin, currentCount)
					vint currentBegin = -1;
					vint currentCount = 0;

					// Determine currentBegin using existing GetParagraphFromY logic
					Rect clipper = renderTarget->GetClipper();
					vint y1 = clipper.Top() - bounds.Top();
					vint y2 = y1 + clipper.Height();

					if (y1 < y2) // Only if there's visible area
					{
						currentBegin = pgCache.GetParagraphFromY(y1, paragraphDistance);
						if (currentBegin != -1)
						{
							// Count consecutive visible paragraphs
							vint y = pgCache.GetParagraphTop(currentBegin, paragraphDistance);
							for (vint i = currentBegin; i < pgCache.GetParagraphCount() && y < y2; i++)
							{
								currentCount++;
								y += pgCache.GetParagraphSize(i).y + paragraphDistance;
							}
						}
					}

					UpdateRenderRangeAndCleanUp(currentBegin, currentCount);
				}

				if (pgCache.heightCorrectionNeeded && previousRenderBegin >= 0 && previousRenderCount > 0)
				{
					auto measuredHeight = pgCache.GetParagraphSize(previousRenderBegin).y;
					lastTotalHeightWithoutParagraphDistance += pgCache.CorrectUnrenderedParagraphHeights(pgCache.GetParagraphCount(), measuredHeight);
				}

				FixMinSize();

				for (auto p : paragraphsToReset)
				{
					NotifyParagraphStyleUpdated(p, 1);
				}
			}

			void GuiDocumentElementRenderer::NotifyParagraphPaddingUpdated(bool value)
			{
				vint defaultHeight = GuiDocumentParagraphCache::GetDefaultHeight();
				paragraphDistance = element->GetParagraphPadding() ? defaultHeight : 0;
			}

			void GuiDocumentElementRenderer::OnElementStateChanged()
			{
				imageCache.ResetCache();
				lastTotalWidth = 0;
				lastTotalHeightWithoutParagraphDistance = pgCache.ResetCache();
				FixMinSize();
			}

			void GuiDocumentElementRenderer::NotifyParagraphUpdateLastTotalWidth(vint index, vint count)
			{
				for (vint i = 0; i < count; i++)
				{
					vint width = pgCache.GetParagraphSize(index + i).x;
					if (lastTotalWidth == width)
					{
						lastTotalWidth = 0;
						break;
					}
				}
			}

			void GuiDocumentElementRenderer::NotifyParagraphTextUpdated(vint index, vint oldCount, vint newCount)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::GuiDocumentElementRenderer::NotifyParagraphTextUpdated(vint, vint, vint)#"
				vint oldParagraphCount = pgCache.GetParagraphCount();
				vint newParagraphCount = element->GetDocument()->paragraphs.Count();

				CHECK_ERROR(oldCount >= 0, ERROR_MESSAGE_PREFIX L"oldCount cannot be negative.");
				CHECK_ERROR(newCount >= 0, ERROR_MESSAGE_PREFIX L"newCount cannot be negative.");
				CHECK_ERROR(0 <= index && index + oldCount <= oldParagraphCount, ERROR_MESSAGE_PREFIX L"index + oldCount is out of range.");
				CHECK_ERROR(0 <= index && index + newCount <= newParagraphCount, ERROR_MESSAGE_PREFIX L"index + newCount is out of range.");
				CHECK_ERROR(newParagraphCount - oldParagraphCount == newCount - oldCount, ERROR_MESSAGE_PREFIX L"newCount - oldCount does not reflect the actual paragraph count changing.");

				imageCache.ResetTextCache(index, oldCount, newCount);
				NotifyParagraphUpdateLastTotalWidth(index, oldCount);
				lastTotalHeightWithoutParagraphDistance += pgCache.ResetTextCache(index, oldCount, newCount);
				FixMinSize();
				UpdateRenderRange(index, oldCount, newCount);

#undef ERROR_MESSAGE_PREFIX
			}

			void GuiDocumentElementRenderer::NotifyParagraphStyleUpdated(TextPos begin, TextPos end)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::GuiDocumentElementRenderer::NotifyParagraphStyleUpdated(vint, TextPos, TextPos)#"
				vint paragraphCount = pgCache.GetParagraphCount();
				CHECK_ERROR(paragraphCount == element->GetDocument()->paragraphs.Count(), ERROR_MESSAGE_PREFIX L"This function can only be called when only text style is updated.");
				CHECK_ERROR(0 <= begin.row && begin.row < paragraphCount, ERROR_MESSAGE_PREFIX L"begin.row is out of range.");
				CHECK_ERROR(0 <= end.row && end.row < paragraphCount, ERROR_MESSAGE_PREFIX L"end.row is out of range.");

				vint count = end.row - begin.row + 1;
				NotifyParagraphUpdateLastTotalWidth(begin.row, count);
				lastTotalHeightWithoutParagraphDistance += pgCache.ResetStyleCache(begin, end);
				FixMinSize();

#undef ERROR_MESSAGE_PREFIX
			}

			void GuiDocumentElementRenderer::NotifyParagraphStyleUpdated(vint index, vint count)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::GuiDocumentElementRenderer::NotifyParagraphTextUpdated(vint, vint, vint)#"
				vint oldParagraphCount = pgCache.GetParagraphCount();
				vint newParagraphCount = element->GetDocument()->paragraphs.Count();

				CHECK_ERROR(count >= 0, ERROR_MESSAGE_PREFIX L"count cannot be negative.");
				CHECK_ERROR(0 <= index && index + count <= newParagraphCount, ERROR_MESSAGE_PREFIX L"index + count is out of range.");
				NotifyParagraphUpdateLastTotalWidth(index, count);
				lastTotalHeightWithoutParagraphDistance += pgCache.ResetStyleCache(index, count);
				FixMinSize();
#undef ERROR_MESSAGE_PREFIX
			}

			Ptr<DocumentHyperlinkRun::Package> GuiDocumentElementRenderer::GetHyperlinkFromPoint(Point point)
			{
				if (!renderTarget) return nullptr;
				vint index = pgCache.GetParagraphFromY(point.y, paragraphDistance);
				vint top = pgCache.GetParagraphTop(index, paragraphDistance);

				auto document = element->GetDocument();
				auto cache = EnsureParagraph(index);
				Point paragraphPoint(point.x, point.y - top);

				vint start = -1;
				vint length = 0;
				if (cache->graphicsParagraph->GetInlineObjectFromPoint(paragraphPoint, start, length))
				{
					return document->GetHyperlink(index, start, start + length);
				}

				vint caret = cache->graphicsParagraph->GetCaretFromPoint(paragraphPoint);
				return document->GetHyperlink(index, caret, caret);
			}

			void GuiDocumentElementRenderer::EnableCaret(TextPos caret, Color color, bool frontSide)
			{
				if (lastCaret != caret || lastCaretColor != color || lastCaretFrontSide != frontSide)
				{
					if (auto cache = pgCache.TryGetParagraphCache(lastCaret.row))
					{
						if (cache->graphicsParagraph)
						{
							cache->graphicsParagraph->DisableCaret();
						}
					}

					lastCaret = caret;
					lastCaretColor = color;
					lastCaretFrontSide = frontSide;

					if (auto cache = pgCache.TryGetParagraphCache(lastCaret.row))
					{
						if (cache->graphicsParagraph)
						{
							cache->graphicsParagraph->EnableCaret(lastCaret.column, lastCaretColor, lastCaretFrontSide);
						}
					}
				}
			}

			void GuiDocumentElementRenderer::DisableCaret()
			{
				if (lastCaret != TextPos(-1, -1))
				{
					auto cache = pgCache.TryGetParagraphCache(lastCaret.row);
					if (cache && cache->graphicsParagraph)
					{
						cache->graphicsParagraph->DisableCaret();
					}
				}
				lastCaret = TextPos(-1, -1);
			}

			bool GuiDocumentElementRenderer::BlinkCaret()
			{
				if (lastCaret != TextPos(-1, -1))
				{
					auto cache = pgCache.TryGetParagraphCache(lastCaret.row);
					if (cache && cache->graphicsParagraph)
					{
						return cache->graphicsParagraph->BlinkCaret();
					}
				}
				return false;
			}

			void GuiDocumentElementRenderer::SetSelection(TextPos begin, TextPos end)
			{
				if (begin > end)
				{
					TextPos t = begin;
					begin = end;
					end = t;
				}
				if (begin == end)
				{
					begin = TextPos(-1, -1);
					end = TextPos(-1, -1);
				}

				if (!renderTarget) return;
				vint paragraphCount = pgCache.GetParagraphCount();
				for (vint i = 0; i < paragraphCount; i++)
				{
					if (begin.row <= i && i <= end.row)
					{
						if (auto cache = pgCache.TryGetParagraphCache(i))
						{
							vint newBegin = i == begin.row ? begin.column : 0;
							vint newEnd = i == end.row ? end.column : cache->fullText.Length();

							if (cache->selectionBegin != newBegin || cache->selectionEnd != newEnd)
							{
								vint selectionBegin = cache->selectionBegin;
								vint selectionEnd = cache->selectionEnd;
								if (newBegin < selectionBegin || selectionBegin == -1) selectionBegin = newBegin;
								if (newEnd > selectionEnd || selectionEnd == -1) selectionEnd = newEnd;
								cache->selectionBegin = newBegin;
								cache->selectionEnd = newEnd;
								if (cache->graphicsParagraph)
								{
									NotifyParagraphStyleUpdated({ i,selectionBegin }, { i,selectionEnd });
								}
							}
						}
					}
					else
					{
						if (auto cache = pgCache.TryGetParagraphCache(i))
						{
							if (cache->selectionBegin != -1 || cache->selectionEnd != -1)
							{
								vint selectionBegin = cache->selectionBegin;
								vint selectionEnd = cache->selectionEnd;
								cache->selectionBegin = -1;
								cache->selectionEnd = -1;
								if (cache->graphicsParagraph)
								{
									NotifyParagraphStyleUpdated({ i,selectionBegin }, { i,selectionEnd });
								}
							}
						}
					}
				}
			}

			TextPos GuiDocumentElementRenderer::CalculateCaret(TextPos comparingCaret, IGuiGraphicsParagraph::CaretRelativePosition position, bool& preferFrontSide)
			{
				if (!renderTarget) return comparingCaret;
				if (auto cache = EnsureParagraph(comparingCaret.row))
				{
					switch (position)
					{
					case IGuiGraphicsParagraph::CaretFirst:
						{
							preferFrontSide = false;
							vint caret = cache->graphicsParagraph->GetCaret(0, IGuiGraphicsParagraph::CaretFirst, preferFrontSide);
							return TextPos(comparingCaret.row, caret);
						}
					case IGuiGraphicsParagraph::CaretLast:
						{
							preferFrontSide = true;
							vint caret = cache->graphicsParagraph->GetCaret(0, IGuiGraphicsParagraph::CaretLast, preferFrontSide);
							return TextPos(comparingCaret.row, caret);
						}
					case IGuiGraphicsParagraph::CaretLineFirst:
						{
							preferFrontSide = false;
							vint caret = cache->graphicsParagraph->GetCaret(comparingCaret.column, IGuiGraphicsParagraph::CaretLineFirst, preferFrontSide);
							return TextPos(comparingCaret.row, caret);
						}
					case IGuiGraphicsParagraph::CaretLineLast:
						{
							preferFrontSide = true;
							vint caret = cache->graphicsParagraph->GetCaret(comparingCaret.column, IGuiGraphicsParagraph::CaretLineLast, preferFrontSide);
							return TextPos(comparingCaret.row, caret);
						}
					case IGuiGraphicsParagraph::CaretMoveUp:
						{
							vint caret = cache->graphicsParagraph->GetCaret(comparingCaret.column, IGuiGraphicsParagraph::CaretMoveUp, preferFrontSide);
							if (caret == comparingCaret.column && comparingCaret.row > 0)
							{
								Rect caretBounds = cache->graphicsParagraph->GetCaretBounds(comparingCaret.column, preferFrontSide);
								auto anotherCache = EnsureParagraph(comparingCaret.row - 1);
								vint height = anotherCache->graphicsParagraph->GetSize().y;
								caret = anotherCache->graphicsParagraph->GetCaretFromPoint(Point(caretBounds.x1, height));
								return TextPos(comparingCaret.row - 1, caret);
							}
							else
							{
								return TextPos(comparingCaret.row, caret);
							}
						}
					case IGuiGraphicsParagraph::CaretMoveDown:
						{
							vint caret = cache->graphicsParagraph->GetCaret(comparingCaret.column, IGuiGraphicsParagraph::CaretMoveDown, preferFrontSide);
							if (caret == comparingCaret.column && comparingCaret.row < pgCache.GetParagraphCount() - 1)
							{
								Rect caretBounds = cache->graphicsParagraph->GetCaretBounds(comparingCaret.column, preferFrontSide);
								auto anotherCache = EnsureParagraph(comparingCaret.row + 1);
								caret = anotherCache->graphicsParagraph->GetCaretFromPoint(Point(caretBounds.x1, 0));
								return TextPos(comparingCaret.row + 1, caret);
							}
							else
							{
								return TextPos(comparingCaret.row, caret);
							}
						}
					case IGuiGraphicsParagraph::CaretMoveLeft:
						{
							preferFrontSide = false;
							vint caret = cache->graphicsParagraph->GetCaret(comparingCaret.column, IGuiGraphicsParagraph::CaretMoveLeft, preferFrontSide);
							if (caret == comparingCaret.column && comparingCaret.row > 0)
							{
								auto anotherCache = EnsureParagraph(comparingCaret.row - 1);
								caret = anotherCache->graphicsParagraph->GetCaret(0, IGuiGraphicsParagraph::CaretLast, preferFrontSide);
								return TextPos(comparingCaret.row - 1, caret);
							}
							else
							{
								return TextPos(comparingCaret.row, caret);
							}
						}
					case IGuiGraphicsParagraph::CaretMoveRight:
						{
							preferFrontSide = true;
							vint caret = cache->graphicsParagraph->GetCaret(comparingCaret.column, IGuiGraphicsParagraph::CaretMoveRight, preferFrontSide);
							if (caret == comparingCaret.column && comparingCaret.row < pgCache.GetParagraphCount() - 1)
							{
								auto anotherCache = EnsureParagraph(comparingCaret.row + 1);
								caret = anotherCache->graphicsParagraph->GetCaret(0, IGuiGraphicsParagraph::CaretFirst, preferFrontSide);
								return TextPos(comparingCaret.row + 1, caret);
							}
							else
							{
								return TextPos(comparingCaret.row, caret);
							}
						}
					}
				}
				return comparingCaret;
			}

			TextPos GuiDocumentElementRenderer::CalculateCaretFromPoint(Point point)
			{
				if (!renderTarget) return TextPos(-1, -1);
				vint index = pgCache.GetParagraphFromY(point.y, paragraphDistance);
				vint top = pgCache.GetParagraphTop(index, paragraphDistance);

				auto cache = EnsureParagraph(index);
				Point paragraphPoint(point.x, point.y - top);
				vint caret = cache->graphicsParagraph->GetCaretFromPoint(paragraphPoint);
				return TextPos(index, caret);
			}

			Rect GuiDocumentElementRenderer::GetCaretBounds(TextPos caret, bool frontSide)
			{
				if (!renderTarget) return Rect();
				auto cache = EnsureParagraph(caret.row);
				if (cache)
				{
					Rect bounds = cache->graphicsParagraph->GetCaretBounds(caret.column, frontSide);
					if (bounds != Rect())
					{
						vint y = pgCache.GetParagraphTop(caret.row, paragraphDistance);
						bounds.y1 += y;
						bounds.y2 += y;
						return bounds;
					}
				}
				return Rect();
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSELEMENT\GUIGRAPHICSDOCUMENTRENDERER_GUIDOCUMENTIMAGECACHE.CPP
***********************************************************************/

namespace vl
{
	using namespace collections;

	namespace presentation
	{
		namespace elements
		{

/***********************************************************************
GuiDocumentImageCache
***********************************************************************/

			GuiDocumentImageCache::GuiDocumentImageCache()
			{
			}

			GuiDocumentImageCache::~GuiDocumentImageCache()
			{
			}

			void GuiDocumentImageCache::Initialize(GuiDocumentElement* _element)
			{
				element = _element;
			}

			void GuiDocumentImageCache::RenderTargetChanged(IGuiGraphicsRenderTarget* oldRenderTarget, IGuiGraphicsRenderTarget* newRenderTarget)
			{
			}

			void GuiDocumentImageCache::ResetCache()
			{
				caches.Resize(0);
				if (auto document = element->GetDocument())
				{
					caches.Resize(document->paragraphs.Count());
				}
			}

			void GuiDocumentImageCache::ResetTextCache(vint index, vint oldCount, vint newCount)
			{
				pg::ParagraphImageCacheArray oldCaches;
				CopyFrom(oldCaches, caches);

				vint paragraphCount = element->GetDocument()->paragraphs.Count();
				caches.Resize(paragraphCount);

				for (vint i = 0; i < paragraphCount; i++)
				{
					if (i < index)
					{
						caches[i] = oldCaches[i];
					}
					else if (i < index + newCount)
					{
						caches[i] = {};
					}
					else
					{
						caches[i] = oldCaches[i - (newCount - oldCount)];
					}
				}
			}

			Ptr<IGuiGraphicsElement> GuiDocumentImageCache::GetImageElement(Ptr<INativeImage> image, vint frameIndex, vint paragraphIndex, vint start)
			{
				auto cache = caches[paragraphIndex];
				if (!cache)
				{
					cache = Ptr(new pg::ParagraphImageCache);
					caches[paragraphIndex] = cache;
				}

				auto key = Tuple(image.Obj(), frameIndex, start);
				vint index = cache->elements.Keys().IndexOf(key);
				if (index == -1)
				{
					auto element = Ptr(GuiImageFrameElement::Create());
					element->SetImage(image, frameIndex);
					element->SetStretch(true);
					cache->elements.Add(key, element);
					return element;
				}
				else
				{
					return cache->elements.Values()[index];
				}
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSELEMENT\GUIGRAPHICSDOCUMENTRENDERER_GUIDOCUMENTPARAGRAPHCACHE.CPP
***********************************************************************/

namespace vl
{
	using namespace collections;

	namespace presentation
	{
		namespace elements
		{

/***********************************************************************
GuiDocumentParagraphCache
***********************************************************************/

			GuiDocumentParagraphCache::GuiDocumentParagraphCache(GuiDocumentElementRenderer* _renderer)
				: renderer(_renderer)
				, callback(_renderer)
				, layoutProvider(GetGuiGraphicsResourceManager()->GetLayoutProvider())
			{
			}

			GuiDocumentParagraphCache::~GuiDocumentParagraphCache()
			{
			}

			vint GuiDocumentParagraphCache::GetDefaultHeight()
			{
				vint defaultHeight = GetCurrentController()->ResourceService()->GetDefaultFont().size;
				if (defaultHeight < 1) defaultHeight = 1;
				return defaultHeight;
			}

			void GuiDocumentParagraphCache::Initialize(GuiDocumentElement* _element)
			{
				element = _element;
			}

			void GuiDocumentParagraphCache::RenderTargetChanged(IGuiGraphicsRenderTarget* oldRenderTarget, IGuiGraphicsRenderTarget* newRenderTarget)
			{
				renderTarget = newRenderTarget;
				// TODO: (enumerable) foreach
				for (vint i = 0; i < paragraphCaches.Count(); i++)
				{
					if (auto cache = paragraphCaches[i].Obj())
					{
						cache->graphicsParagraph = nullptr;
						cache->invalidation = true;
					}
				}
			}

			vint GuiDocumentParagraphCache::GetParagraphCount()
			{
				return paragraphCaches.Count();
			}

			Ptr<pg::ParagraphCache> GuiDocumentParagraphCache::TryGetParagraphCache(vint paragraphIndex)
			{
				if (paragraphIndex < 0 || paragraphIndex >= paragraphCaches.Count()) return nullptr;
				return paragraphCaches[paragraphIndex];
			}

			Ptr<pg::ParagraphCache> GuiDocumentParagraphCache::GetParagraphCache(vint paragraphIndex, bool requireParagraph)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::GuiDocumentParagraphCache::GetParagraphCache(vint)#"
				auto cache = paragraphCaches[paragraphIndex];
				if (requireParagraph)
				{
					CHECK_ERROR(cache && cache->graphicsParagraph && cache->invalidation.TryGet<bool>() && cache->invalidation.Get<bool>() == false, ERROR_MESSAGE_PREFIX L"The specified paragraph is not created.");
				}
				return cache;
#undef ERROR_MESSAGE_PREFIX
			}

			Size GuiDocumentParagraphCache::GetParagraphSize(vint paragraphIndex)
			{
				return paragraphSizes[paragraphIndex].cachedSize;
			}

			vint GuiDocumentParagraphCache::GetParagraphTopWithoutParagraphDistance(vint paragraphIndex)
			{
				if (paragraphIndex >= validCachedTops)
				{
					vint currentTop = 0;
					if (validCachedTops > 0)
					{
						auto size = paragraphSizes[validCachedTops - 1];
						currentTop = size.cachedTopWithoutParagraphDistance + size.cachedSize.y;
					}

					for (vint i = validCachedTops; i <= paragraphIndex; i++)
					{
						auto& size = paragraphSizes[i];
						size.cachedTopWithoutParagraphDistance = currentTop;
						currentTop += size.cachedSize.y;
					}

					validCachedTops = paragraphIndex + 1;
				}
				return paragraphSizes[paragraphIndex].cachedTopWithoutParagraphDistance;
			}

			vint GuiDocumentParagraphCache::GetParagraphTop(vint paragraphIndex, vint paragraphDistance)
			{
				return GetParagraphTopWithoutParagraphDistance(paragraphIndex) + paragraphIndex * paragraphDistance;
			}

			vint GuiDocumentParagraphCache::ResetCache()
			{
				nameCallbackIdMap.Clear();
				freeCallbackIds.Clear();
				usedCallbackIds = 0;

				auto document = element ? element->GetDocument() : nullptr;
				if (document && document->paragraphs.Count() > 0)
				{
					paragraphCaches.Resize(0);
					paragraphCaches.Resize(document->paragraphs.Count());
					paragraphSizes.Resize(document->paragraphs.Count());

					vint defaultHeight = GetDefaultHeight();
					for (vint i = 0; i < paragraphSizes.Count(); i++)
					{
						paragraphSizes[i] = { (i * defaultHeight),{0,defaultHeight}};
					}

					validCachedTops = document->paragraphs.Count();
					heightCorrectionNeeded = true;
					return document->paragraphs.Count() * defaultHeight;
				}
				else
				{
					paragraphCaches.Resize(0);
					paragraphSizes.Resize(0);
					validCachedTops = 0;
					heightCorrectionNeeded = false;
					return 0;
				}
			}

			vint GuiDocumentParagraphCache::ResetTextCache(vint index, vint oldCount, vint newCount)
			{
				for (vint i = 0; i < oldCount; i++)
				{
					if (auto cache = paragraphCaches[i + index])
					{
						// TODO: (enumerable) foreach on dictionary
						for (vint j = 0; j < cache->embeddedObjects.Count(); j++)
						{
							auto id = cache->embeddedObjects.Keys()[j];
							auto name = cache->embeddedObjects.Values()[j]->name;
							nameCallbackIdMap.Remove(name);
							freeCallbackIds.Add(id);
						}
					}
				}

				if (oldCount == newCount)
				{
					for (vint i = 0; i < oldCount; i++)
					{
						paragraphCaches[index + i] = nullptr;
					}
					return 0;
				}
				else
				{
					vint defaultHeight = GetDefaultHeight();
					pg::ParagraphCacheArray oldCaches;
					pg::ParagraphSizeArray oldSizes;

					CopyFrom(oldCaches, paragraphCaches);
					CopyFrom(oldSizes, paragraphSizes);

					vint paragraphCount = element->GetDocument()->paragraphs.Count();
					paragraphCaches.Resize(paragraphCount);
					paragraphSizes.Resize(paragraphCount);

					vint paragraphTop = GetParagraphTopWithoutParagraphDistance(index);
					for (vint i = 0; i < paragraphCount; i++)
					{
						if (i < index)
						{
							paragraphCaches[i] = oldCaches[i];
							paragraphSizes[i] = oldSizes[i];
						}
						else if (i < index + newCount)
						{
							// updateText must be true, ensured in GuiDocumentElementRenderer::NotifyParagraphUpdated
							paragraphCaches[i] = nullptr;
							paragraphSizes[i] = { (paragraphTop + (i - index) * defaultHeight),{0,defaultHeight} };
						}
						else
						{
							paragraphCaches[i] = oldCaches[i - (newCount - oldCount)];
							paragraphSizes[i] = oldSizes[i - (newCount - oldCount)];
						}
					}
					validCachedTops = index + newCount;
					heightCorrectionNeeded = true;

					vint oldUpdatedTotalHeight = 0;
					for (vint i = 0; i < oldCount; i++)
					{
						oldUpdatedTotalHeight += oldSizes[index + i].cachedSize.y;
					}
					return newCount * defaultHeight - oldUpdatedTotalHeight;
				}
			}

			vint GuiDocumentParagraphCache::ResetStyleCache(TextPos begin, TextPos end)
			{
				for (vint i = begin.row; i <= end.row; i++)
				{
					if (auto cache = paragraphCaches[i])
					{
						vint rangeBegin = i == begin.row ? begin.column : 0;
						vint rangeEnd = i == end.row ? end.column : cache->fullText.Length();
						cache->invalidation.Apply(Overloading(
							[&, this](bool value)
							{
								if (!value)
								{
									cache->invalidation = Pair(rangeBegin, rangeEnd);
								}
							},
							[&, this](collections::Pair<vint, vint> range)
							{
								if (rangeBegin > range.key) rangeBegin = range.key;
								if (rangeEnd < range.value) rangeEnd = range.value;
								cache->invalidation = Pair(rangeBegin, rangeEnd);
							}
						));
					}
				}
				return 0;
			}

			vint GuiDocumentParagraphCache::ResetStyleCache(vint index, vint count)
			{
				for (vint i = 0; i < count; i++)
				{
					if (auto cache = paragraphCaches[index + i])
					{
						cache->invalidation = true;
					}
				}
				return 0;
			}

			vint GuiDocumentParagraphCache::EnsureParagraph(vint paragraphIndex, vint maxWidth)
			{
				auto paragraph = element->GetDocument()->paragraphs[paragraphIndex];
				auto cache = paragraphCaches[paragraphIndex];
				if (!cache)
				{
					cache = Ptr(new pg::ParagraphCache);
					cache->fullText = paragraph->GetTextForCaret();
					paragraphCaches[paragraphIndex] = cache;
				}

				if (!cache->graphicsParagraph)
				{
					auto paragraphText = cache->fullText;
					if (auto passwordChar = element->GetPasswordChar())
					{
						Array<wchar_t> passwordText(paragraphText.Length() + 1);
						for (vint i = 0; i < paragraphText.Length(); i++)
						{
							passwordText[i] = passwordChar;
						}
						passwordText[paragraphText.Length()] = 0;
						paragraphText = &passwordText[0];
					}
					cache->graphicsParagraph = layoutProvider->CreateParagraph(paragraphText, renderTarget, callback);
					cache->invalidation = true;
				}

				cache->invalidation.Apply(Overloading(
					[&, this](bool value)
					{
						if (value)
						{
							cache->invalidation = false;
							renderer->ApplyPropertiesOnParagraph(paragraphIndex, 0, cache->fullText.Length(), maxWidth);
						}
						else
						{
							cache->graphicsParagraph->SetMaxWidth(maxWidth);
						}
					},
					[&, this](collections::Pair<vint, vint> range)
					{
						cache->invalidation = false;
						renderer->ApplyPropertiesOnParagraph(paragraphIndex, range.key, range.value, maxWidth);
					}
				));

				auto& cachedSize = paragraphSizes[paragraphIndex];
				Size oldSize = cachedSize.cachedSize;
				Size newSize = cache->graphicsParagraph->GetSize();

				vint defaultHeight = GetDefaultHeight();
				if(newSize.y < defaultHeight)
				{
					newSize.y = defaultHeight;
				}
				cachedSize.cachedSize = newSize;
				if (oldSize.y != newSize.y && validCachedTops > paragraphIndex + 1)
				{
					validCachedTops = paragraphIndex + 1;
				}
				return newSize.y - oldSize.y;
			}

			vint GuiDocumentParagraphCache::CorrectUnrenderedParagraphHeights(vint endIndex, vint measuredHeight)
			{
				heightCorrectionNeeded = false;
				vint totalDelta = 0;
				vint firstChanged = -1;
				for (vint i = 0; i < endIndex; i++)
				{
					if (!paragraphCaches[i])
					{
						auto& size = paragraphSizes[i];
						vint delta = measuredHeight - size.cachedSize.y;
						if (delta != 0)
						{
							totalDelta += delta;
							size.cachedSize.y = measuredHeight;
							if (firstChanged == -1)
							{
								firstChanged = i;
							}
						}
					}
				}
				if (firstChanged != -1 && validCachedTops > firstChanged + 1)
				{
					validCachedTops = firstChanged + 1;
				}
				return totalDelta;
			}

			vint GuiDocumentParagraphCache::GetParagraphFromY(vint y, vint paragraphDistance)
			{
				auto document = element ? element->GetDocument() : nullptr;
				if (!document || document->paragraphs.Count() == 0) return -1;

				vint start = 0;
				vint end = paragraphSizes.Count() - 1;

				if (0 < validCachedTops && validCachedTops <= paragraphSizes.Count())
				{
					vint index = validCachedTops - 1;
					vint top = GetParagraphTop(index, paragraphDistance);
					auto size = paragraphSizes[index].cachedSize;
					if (y < top)
					{
						if (index < 1) return 0;
						end = index - 1;
					}
					else if (y < top + size.y + paragraphDistance)
					{
						return index;
					}
					else
					{
						if (index >= paragraphSizes.Count() - 1) return paragraphSizes.Count() - 1;
						start = validCachedTops;
					}
				}

				if (start >= end) return end;
				while (true)
				{
					vint mid = (start + end) / 2;
					vint top = GetParagraphTop(mid, paragraphDistance);
					auto size = paragraphSizes[mid].cachedSize;
					if (y < top)
					{
						end = mid - 1;
						if (start >= end) return start;
					}
					else if (y < top + size.y + paragraphDistance)
					{
						return mid;
					}
					else
					{
						start = mid + 1;
						if (start >= end) return end;
					}
				}
			}

			void GuiDocumentParagraphCache::ReleaseParagraphs(vint index, vint count)
			{
				for (vint i = 0; i < count; i++)
				{
					vint paragraphIndex = index + i;
					if (paragraphIndex >= 0 && paragraphIndex < paragraphCaches.Count())
					{
						auto cache = paragraphCaches[paragraphIndex];
						if (cache) // Check if cache itself is null per UPDATE guidance
						{
							cache->graphicsParagraph = nullptr; // Release only the rendering object
							// Preserve all other data: fullText, embeddedObjects, selectionBegin/selectionEnd
						}
					}
				}
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSELEMENT\GUIGRAPHICSDOCUMENTRENDERER_SETPROPERTIESVISITOR.CPP
***********************************************************************/

namespace vl
{
	using namespace collections;

	namespace presentation
	{
		namespace elements
		{

/***********************************************************************
SetPropertiesVisitor
***********************************************************************/

			namespace visitors
			{
				class SetPropertiesVisitor : public Object, public DocumentRun::IVisitor
				{
					typedef DocumentModel::ResolvedStyle					ResolvedStyle;
				public:
					vint							start = 0;
					vint							length = 0;
					vint							selectionBegin;
					vint							selectionEnd;
					vint							rangeBegin;
					vint							rangeEnd;
					List<ResolvedStyle>				styles;

					DocumentModel*					model;
					GuiDocumentParagraphCache*		paragraphCache;
					GuiDocumentImageCache*			imageCache;
					Ptr<pg::ParagraphCache>			cache;
					IGuiGraphicsParagraph*			paragraph;
					vint							paragraphIndex;

					SetPropertiesVisitor(
						DocumentModel* _model,
						GuiDocumentParagraphCache* _paragraphCache,
						GuiDocumentImageCache* _imageCache,
						Ptr<pg::ParagraphCache> _cache,
						vint _paragraphIndex,
						vint _selectionBegin,
						vint _selectionEnd,
						vint _rangeBegin,
						vint _rangeEnd
					)
						: model(_model)
						, paragraphCache(_paragraphCache)
						, imageCache(_imageCache)
						, cache(_cache)
						, paragraphIndex(_paragraphIndex)
						, paragraph(_cache->graphicsParagraph.Obj())
						, selectionBegin(_selectionBegin)
						, selectionEnd(_selectionEnd)
						, rangeBegin(_rangeBegin)
						, rangeEnd(_rangeEnd)
					{
						ResolvedStyle style;
						style = model->GetStyle(DocumentModel::DefaultStyleName, style);
						styles.Add(style);
					}

					void VisitContainer(DocumentContainerRun* run)
					{
						for (auto subRun : run->runs)
						{
							subRun->Accept(this);
						}
					}

					void ApplyStyle(vint start, vint length, const ResolvedStyle& style)
					{
						paragraph->SetFont(start, length, style.style.fontFamily);
						paragraph->SetSize(start, length, style.style.size);
						paragraph->SetStyle(start, length,
							(IGuiGraphicsParagraph::TextStyle)
							((style.style.bold ? IGuiGraphicsParagraph::Bold : 0)
							| (style.style.italic ? IGuiGraphicsParagraph::Italic : 0)
							| (style.style.underline ? IGuiGraphicsParagraph::Underline : 0)
							| (style.style.strikeline ? IGuiGraphicsParagraph::Strikeline : 0)
							));
					}

					void ApplyColor(vint start, vint length, const ResolvedStyle& style)
					{
						paragraph->SetColor(start, length, style.color);
						paragraph->SetBackgroundColor(start, length, style.backgroundColor);
					}

					void Visit(DocumentTextRun* run)override
					{
						length = run->GetRepresentationText().Length();
						if (length > 0 && start < rangeEnd && rangeBegin < start + length)
						{
							ResolvedStyle style = styles[styles.Count() - 1];
							ApplyStyle(start, length, style);
							ApplyColor(start, length, style);

							vint styleStart = start;
							vint styleEnd = styleStart + length;
							if (styleStart < selectionEnd && selectionBegin < styleEnd)
							{
								vint s2 = styleStart > selectionBegin ? styleStart : selectionBegin;
								vint s3 = selectionEnd < styleEnd ? selectionEnd : styleEnd;

								if (s2 < s3)
								{
									ResolvedStyle selectionStyle = model->GetStyle(DocumentModel::SelectionStyleName, style);
									ApplyColor(s2, s3 - s2, selectionStyle);
								}
							}
						}
						start += length;
					}

					void Visit(DocumentStylePropertiesRun* run)override
					{
						ResolvedStyle style = styles[styles.Count() - 1];
						style = model->GetStyle(run->style, style);
						styles.Add(style);
						VisitContainer(run);
						styles.RemoveAt(styles.Count() - 1);
					}

					void Visit(DocumentStyleApplicationRun* run)override
					{
						ResolvedStyle style = styles[styles.Count() - 1];
						style = model->GetStyle(run->styleName, style);
						styles.Add(style);
						VisitContainer(run);
						styles.RemoveAt(styles.Count() - 1);
					}

					void Visit(DocumentHyperlinkRun* run)override
					{
						ResolvedStyle style = styles[styles.Count() - 1];
						style = model->GetStyle(run->styleName, style);
						styles.Add(style);
						VisitContainer(run);
						styles.RemoveAt(styles.Count() - 1);
					}

					void Visit(DocumentImageRun* run)override
					{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::visitors::SetPropertiesVisitor::Visit(DocumentImageRun*)#"
						length = run->GetRepresentationText().Length();
						if (start < rangeEnd && rangeBegin < start + length)
						{
							IGuiGraphicsParagraph::InlineObjectProperties properties;
							properties.size = run->GetSize();
							properties.baseline = run->baseline;
							properties.breakCondition = IGuiGraphicsParagraph::Alone;
							properties.backgroundImage = imageCache->GetImageElement(run->image, run->frameIndex, paragraphIndex, start);

							ResolvedStyle style = styles[styles.Count() - 1];
							if (start < selectionEnd && selectionBegin < start + length)
							{
								style = model->GetStyle(DocumentModel::SelectionStyleName, style);
							}
							properties.backgroundColor = style.backgroundColor;

							bool result = paragraph->SetInlineObject(start, length, properties);
							CHECK_ERROR(result, ERROR_MESSAGE_PREFIX L"The specified range has already been occupied by another inline object.");
						}
						start += length;
#undef ERROR_MESSAGE_PREFIX
					}

					void Visit(DocumentEmbeddedObjectRun* run)override
					{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::visitors::SetPropertiesVisitor::Visit(DocumentEmbeddedObjectRun*)#"
						length = run->GetRepresentationText().Length();
						if (start < rangeEnd && rangeBegin < start + length)
						{
							IGuiGraphicsParagraph::InlineObjectProperties properties;
							properties.breakCondition = IGuiGraphicsParagraph::Alone;

							if (run->name != L"")
							{
								vint index = paragraphCache->nameCallbackIdMap.Keys().IndexOf(run->name);
								if (index != -1)
								{
									auto id = paragraphCache->nameCallbackIdMap.Values()[index];
									index = cache->embeddedObjects.Keys().IndexOf(id);
									if (index != -1)
									{
										auto eo = cache->embeddedObjects.Values()[index];
										if (eo->start == start)
										{
											properties.size = eo->size;
											properties.callbackId = id;
										}
									}
								}
								else
								{
									auto eo = Ptr(new pg::EmbeddedObject);
									eo->name = run->name;
									eo->size = Size(0, 0);
									eo->start = start;

									vint id = -1;
									vint count = paragraphCache->freeCallbackIds.Count();
									if (count > 0)
									{
										id = paragraphCache->freeCallbackIds[count - 1];
										paragraphCache->freeCallbackIds.RemoveAt(count - 1);
									}
									else
									{
										id = paragraphCache->usedCallbackIds++;
									}

									paragraphCache->nameCallbackIdMap.Add(eo->name, id);
									cache->embeddedObjects.Add(id, eo);
									properties.callbackId = id;
								}
							}

							ResolvedStyle style = styles[styles.Count() - 1];
							if (start < selectionEnd && selectionBegin < start + length)
							{
								style = model->GetStyle(DocumentModel::SelectionStyleName, style);
							}
							properties.backgroundColor = style.backgroundColor;

							bool result = paragraph->SetInlineObject(start, length, properties);
							CHECK_ERROR(result, ERROR_MESSAGE_PREFIX L"The specified range has already been occupied by another inline object.");
						}
						start += length;
#undef ERROR_MESSAGE_PREFIX
					}

					void Visit(DocumentParagraphRun* run)override
					{
						VisitContainer(run);
					}
				};

				vint SetProperties(
					DocumentModel* model,
					GuiDocumentParagraphCache* paragraphCache,
					GuiDocumentImageCache* imageCache,
					Ptr<pg::ParagraphCache> cache,
					vint paragraphIndex,
					Ptr<DocumentParagraphRun> run,
					vint selectionBegin,
					vint selectionEnd,
					vint rangeBegin,
					vint rangeEnd
				)
				{
					SetPropertiesVisitor visitor(model, paragraphCache, imageCache, cache, paragraphIndex, selectionBegin, selectionEnd, rangeBegin, rangeEnd);
					run->Accept(&visitor);
					return visitor.length;
				}
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSELEMENT\GUIGRAPHICSELEMENT.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace elements
		{
			using namespace collections;

/***********************************************************************
GuiFocusRectangleElement
***********************************************************************/

			GuiFocusRectangleElement::GuiFocusRectangleElement()
			{
			}

/***********************************************************************
GuiSolidBorderElement
***********************************************************************/

			GuiSolidBorderElement::GuiSolidBorderElement()
				:color(0, 0, 0)
			{
			}

			Color GuiSolidBorderElement::GetColor()
			{
				return color;
			}

			void GuiSolidBorderElement::SetColor(Color value)
			{
				if(color!=value)
				{
					color=value;
					InvokeOnElementStateChanged();
				}
			}
			
			ElementShape GuiSolidBorderElement::GetShape()
			{
				return shape;
			}

			void GuiSolidBorderElement::SetShape(ElementShape value)
			{
				shape=value;
			}

/***********************************************************************
Gui3DBorderElement
***********************************************************************/

			Gui3DBorderElement::Gui3DBorderElement()
			{
			}

			Color Gui3DBorderElement::GetColor1()
			{
				return color1;
			}

			void Gui3DBorderElement::SetColor1(Color value)
			{
				SetColors(value, color2);
			}

			Color Gui3DBorderElement::GetColor2()
			{
				return color2;
			}

			void Gui3DBorderElement::SetColor2(Color value)
			{
				SetColors(color1, value);
			}

			void Gui3DBorderElement::SetColors(Color value1, Color value2)
			{
				if(color1!=value1 || color2!=value2)
				{
					color1=value1;
					color2=value2;
					InvokeOnElementStateChanged();
				}
			}

/***********************************************************************
Gui3DSplitterElement
***********************************************************************/

			Gui3DSplitterElement::Gui3DSplitterElement()
				:direction(Horizontal)
			{
			}

			Color Gui3DSplitterElement::GetColor1()
			{
				return color1;
			}

			void Gui3DSplitterElement::SetColor1(Color value)
			{
				SetColors(value, color2);
			}

			Color Gui3DSplitterElement::GetColor2()
			{
				return color2;
			}

			void Gui3DSplitterElement::SetColor2(Color value)
			{
				SetColors(color1, value);
			}

			void Gui3DSplitterElement::SetColors(Color value1, Color value2)
			{
				if(color1!=value1 || color2!=value2)
				{
					color1=value1;
					color2=value2;
					InvokeOnElementStateChanged();
				}
			}

			Gui3DSplitterElement::Direction Gui3DSplitterElement::GetDirection()
			{
				return direction;
			}

			void Gui3DSplitterElement::SetDirection(Direction value)
			{
				if(direction!=value)
				{
					direction=value;
					InvokeOnElementStateChanged();
				}
			}

/***********************************************************************
GuiSolidBackgroundElement
***********************************************************************/

			GuiSolidBackgroundElement::GuiSolidBackgroundElement()
				:color(255, 255, 255)
			{
			}

			Color GuiSolidBackgroundElement::GetColor()
			{
				return color;
			}

			void GuiSolidBackgroundElement::SetColor(Color value)
			{
				if(color!=value)
				{
					color=value;
					InvokeOnElementStateChanged();
				}
			}
			
			ElementShape GuiSolidBackgroundElement::GetShape()
			{
				return shape;
			}

			void GuiSolidBackgroundElement::SetShape(ElementShape value)
			{
				shape=value;
			}

/***********************************************************************
GuiGradientBackgroundElement
***********************************************************************/

			GuiGradientBackgroundElement::GuiGradientBackgroundElement()
				:direction(Horizontal)
			{
			}

			Color GuiGradientBackgroundElement::GetColor1()
			{
				return color1;
			}

			void GuiGradientBackgroundElement::SetColor1(Color value)
			{
				SetColors(value, color2);
			}

			Color GuiGradientBackgroundElement::GetColor2()
			{
				return color2;
			}

			void GuiGradientBackgroundElement::SetColor2(Color value)
			{
				SetColors(color1, value);
			}

			void GuiGradientBackgroundElement::SetColors(Color value1, Color value2)
			{
				if(color1!=value1 || color2!=value2)
				{
					color1=value1;
					color2=value2;
					InvokeOnElementStateChanged();
				}
			}

			GuiGradientBackgroundElement::Direction GuiGradientBackgroundElement::GetDirection()
			{
				return direction;
			}

			void GuiGradientBackgroundElement::SetDirection(Direction value)
			{
				if(direction!=value)
				{
					direction=value;
					InvokeOnElementStateChanged();
				}
			}
			
			ElementShape GuiGradientBackgroundElement::GetShape()
			{
				return shape;
			}

			void GuiGradientBackgroundElement::SetShape(ElementShape value)
			{
				shape=value;
			}

/***********************************************************************
GuiInnerShadowElement
***********************************************************************/

			GuiInnerShadowElement::GuiInnerShadowElement()
			{
			}

			Color GuiInnerShadowElement::GetColor()
			{
				return color;
			}

			void GuiInnerShadowElement::SetColor(Color value)
			{
				if (color != value)
				{
					color = value;
					InvokeOnElementStateChanged();
				}
			}

			vint GuiInnerShadowElement::GetThickness()
			{
				return thickness;
			}

			void GuiInnerShadowElement::SetThickness(vint value)
			{
				if (thickness != value)
				{
					thickness = value;
					InvokeOnElementStateChanged();
				}
			}

/***********************************************************************
GuiSolidLabelElement
***********************************************************************/

			GuiSolidLabelElement::GuiSolidLabelElement()
				:color(0, 0, 0)
				,hAlignment(Alignment::Left)
				,vAlignment(Alignment::Top)
				,wrapLine(false)
				,ellipse(false)
				,multiline(false)
				,wrapLineHeightCalculation(false)
			{
				fontProperties.fontFamily=L"Lucida Console";
				fontProperties.size=12;
			}

			Color GuiSolidLabelElement::GetColor()
			{
				return color;
			}

			void GuiSolidLabelElement::SetColor(Color value)
			{
				if(color!=value)
				{
					color=value;
					InvokeOnElementStateChanged();
				}
			}

			const FontProperties& GuiSolidLabelElement::GetFont()
			{
				return fontProperties;
			}

			void GuiSolidLabelElement::SetFont(const FontProperties& value)
			{
				if(fontProperties!=value)
				{
					fontProperties=value;
					InvokeOnElementStateChanged();
				}
			}

			const WString& GuiSolidLabelElement::GetText()
			{
				return text;
			}

			void GuiSolidLabelElement::SetText(const WString& value)
			{
				if(text!=value)
				{
					text=value;
					InvokeOnElementStateChanged();
				}
			}

			Alignment GuiSolidLabelElement::GetHorizontalAlignment()
			{
				return hAlignment;
			}

			Alignment GuiSolidLabelElement::GetVerticalAlignment()
			{
				return vAlignment;
			}

			void GuiSolidLabelElement::SetHorizontalAlignment(Alignment value)
			{
				SetAlignments(value, vAlignment);
			}

			void GuiSolidLabelElement::SetVerticalAlignment(Alignment value)
			{
				SetAlignments(hAlignment, value);
			}

			void GuiSolidLabelElement::SetAlignments(Alignment horizontal, Alignment vertical)
			{
				if(hAlignment!=horizontal || vAlignment!=vertical)
				{
					hAlignment=horizontal;
					vAlignment=vertical;
					InvokeOnElementStateChanged();
				}
			}

			bool GuiSolidLabelElement::GetWrapLine()
			{
				return wrapLine;
			}

			void GuiSolidLabelElement::SetWrapLine(bool value)
			{
				if(wrapLine!=value)
				{
					wrapLine=value;
					InvokeOnElementStateChanged();
				}
			}

			bool GuiSolidLabelElement::GetEllipse()
			{
				return ellipse;
			}

			void GuiSolidLabelElement::SetEllipse(bool value)
			{
				if(ellipse!=value)
				{
					ellipse=value;
					InvokeOnElementStateChanged();
				}
			}

			bool GuiSolidLabelElement::GetMultiline()
			{
				return multiline;
			}

			void GuiSolidLabelElement::SetMultiline(bool value)
			{
				if(multiline!=value)
				{
					multiline=value;
					InvokeOnElementStateChanged();
				}
			}

			bool GuiSolidLabelElement::GetWrapLineHeightCalculation()
			{
				return wrapLineHeightCalculation;
			}

			void GuiSolidLabelElement::SetWrapLineHeightCalculation(bool value)
			{
				if(wrapLineHeightCalculation!=value)
				{
					wrapLineHeightCalculation=value;
					InvokeOnElementStateChanged();
				}
			}

/***********************************************************************
GuiImageFrameElement
***********************************************************************/

			GuiImageFrameElement::GuiImageFrameElement()
				: frameIndex(0)
				, hAlignment(Alignment::Left)
				, vAlignment(Alignment::Top)
				, stretch(false)
				, enabled(true)
			{
			}

			Ptr<INativeImage> GuiImageFrameElement::GetImage()
			{
				return image;
			}

			vint GuiImageFrameElement::GetFrameIndex()
			{
				return frameIndex;
			}

			void GuiImageFrameElement::SetImage(Ptr<INativeImage> value)
			{
				SetImage(value, frameIndex);
			}

			void GuiImageFrameElement::SetFrameIndex(vint value)
			{
				SetImage(image, value);
			}

			void GuiImageFrameElement::SetImage(Ptr<INativeImage> _image, vint _frameIndex)
			{
				if (image != _image || frameIndex != _frameIndex)
				{
					if (!_image)
					{
						image = nullptr;
						frameIndex = 0;
					}
					else if (0 <= _frameIndex)
					{
						// do not check frame count because
						// on remote protocol metadata could have not been loaded yet
						image = _image;
						frameIndex = _frameIndex;
					}
					InvokeOnElementStateChanged();
				}
			}

			Alignment GuiImageFrameElement::GetHorizontalAlignment()
			{
				return hAlignment;
			}

			Alignment GuiImageFrameElement::GetVerticalAlignment()
			{
				return vAlignment;
			}

			void GuiImageFrameElement::SetHorizontalAlignment(Alignment value)
			{
				SetAlignments(value, vAlignment);
			}

			void GuiImageFrameElement::SetVerticalAlignment(Alignment value)
			{
				SetAlignments(hAlignment, value);
			}

			void GuiImageFrameElement::SetAlignments(Alignment horizontal, Alignment vertical)
			{
				if (hAlignment != horizontal || vAlignment != vertical)
				{
					hAlignment = horizontal;
					vAlignment = vertical;
					InvokeOnElementStateChanged();
				}
			}

			bool GuiImageFrameElement::GetStretch()
			{
				return stretch;
			}

			void GuiImageFrameElement::SetStretch(bool value)
			{
				if (stretch != value)
				{
					stretch = value;
					InvokeOnElementStateChanged();
				}
			}

			bool GuiImageFrameElement::GetEnabled()
			{
				return enabled;
			}

			void GuiImageFrameElement::SetEnabled(bool value)
			{
				if (enabled != value)
				{
					enabled = value;
					InvokeOnElementStateChanged();
				}
			}

/***********************************************************************
GuiPolygonElement
***********************************************************************/

			GuiPolygonElement::GuiPolygonElement()
			{
			}

			Size GuiPolygonElement::GetSize()
			{
				return size;
			}

			void GuiPolygonElement::SetSize(Size value)
			{
				if(size!=value)
				{
					size=value;
					InvokeOnElementStateChanged();
				}
			}

			const Point& GuiPolygonElement::GetPoint(vint index)
			{
				return points[index];
			}

			vint GuiPolygonElement::GetPointCount()
			{
				return points.Count();
			}

			void GuiPolygonElement::SetPoints(const Point* p, vint count)
			{
				points.Resize(count);
				if(count>0)
				{
					memcpy(&points[0], p, sizeof(*p)*count);
				}
				InvokeOnElementStateChanged();
			}

			const GuiPolygonElement::PointArray& GuiPolygonElement::GetPointsArray()
			{
				return points;
			}

			void GuiPolygonElement::SetPointsArray(const PointArray& value)
			{
				CopyFrom(points, value);
				InvokeOnElementStateChanged();
			}

			Color GuiPolygonElement::GetBorderColor()
			{
				return borderColor;
			}

			void GuiPolygonElement::SetBorderColor(Color value)
			{
				if(borderColor!=value)
				{
					borderColor=value;
					InvokeOnElementStateChanged();
				}
			}

			Color GuiPolygonElement::GetBackgroundColor()
			{
				return backgroundColor;
			}

			void GuiPolygonElement::SetBackgroundColor(Color value)
			{
				if(backgroundColor!=value)
				{
					backgroundColor=value;
					InvokeOnElementStateChanged();
				}
			}
		}
	}
}

/***********************************************************************
.\GRAPHICSELEMENT\GUIGRAPHICSELEMENTINTERFACES.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace elements
		{
			using namespace collections;

/***********************************************************************
GuiGraphicsRenderTarget
***********************************************************************/

			bool GuiGraphicsRenderTarget::IsInHostedRendering()
			{
				return hostedRendering;
			}

			void GuiGraphicsRenderTarget::StartHostedRendering()
			{
				CHECK_ERROR(!hostedRendering && !rendering, L"vl::presentation::elements::GuiGraphicsRenderTarget::StartHostedRendering()#Wrong timing to call this function.");
				hostedRendering = true;
				StartRenderingOnNativeWindow();
			}

			RenderTargetFailure GuiGraphicsRenderTarget::StopHostedRendering()
			{
				CHECK_ERROR(hostedRendering && !rendering, L"vl::presentation::elements::GuiGraphicsRenderTarget::StopHostedRendering()#Wrong timing to call this function.");
				hostedRendering = false;
				return StopRenderingOnNativeWindow();
			}

			void GuiGraphicsRenderTarget::HostedRenderingIdle()
			{
			}

			void GuiGraphicsRenderTarget::StartRendering()
			{
				CHECK_ERROR(!rendering, L"vl::presentation::elements::GuiGraphicsRenderTarget::StartRendering()#Wrong timing to call this function.");
				rendering = true;
				if (!hostedRendering)
				{
					StartRenderingOnNativeWindow();
				}
			}

			RenderTargetFailure GuiGraphicsRenderTarget::StopRendering()
			{
				CHECK_ERROR(rendering, L"vl::presentation::elements::GuiGraphicsRenderTarget::StopRendering()#Wrong timing to call this function.");
				rendering = false;
				if (!hostedRendering)
				{
					return StopRenderingOnNativeWindow();
				}
				return RenderTargetFailure::None;
			}

			void GuiGraphicsRenderTarget::PushClipper(Rect clipper, reflection::DescriptableObject* generator)
			{
				if (clipperCoverWholeTargetCounter > 0)
				{
					clipperCoverWholeTargetCounter++;
				}
				else
				{
					Rect currentClipper = GetClipper().Intersect(clipper);
					if (currentClipper.x1 < currentClipper.x2 && currentClipper.y1 < currentClipper.y2)
					{
						clippers.Add(currentClipper);
						AfterPushedClipper(clipper, currentClipper, generator);
					}
					else
					{
						clipperCoverWholeTargetCounter++;
						AfterPushedClipperAndBecameInvalid(clipper, generator);
					}
				}
			}

			void GuiGraphicsRenderTarget::PopClipper(reflection::DescriptableObject* generator)
			{
				if (clipperCoverWholeTargetCounter > 0)
				{
					clipperCoverWholeTargetCounter--;
					if (clipperCoverWholeTargetCounter == 0)
					{
						AfterPoppedClipperAndBecameValid(GetClipper(), clippers.Count() > 0, generator);
					}
				}
				else if (clippers.Count() > 0)
				{
					clippers.RemoveAt(clippers.Count() - 1);
					AfterPoppedClipper(GetClipper(), clippers.Count() > 0, generator);
				}
			}

			Rect GuiGraphicsRenderTarget::GetClipper()
			{
				if (clipperCoverWholeTargetCounter > 0)
				{
					return { {-1,-1},{0,0} };
				}
				else if (clippers.Count() == 0)
				{
					return Rect(Point(0, 0), GetCanvasSize());
				}
				else
				{
					return clippers[clippers.Count() - 1];
				}
			}

			bool GuiGraphicsRenderTarget::IsClipperCoverWholeTarget()
			{
				return clipperCoverWholeTargetCounter > 0;
			}
		}
	}
}


/***********************************************************************
.\GRAPHICSELEMENT\GUIGRAPHICSRESOURCEMANAGER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace elements
		{
			using namespace collections;

/***********************************************************************
GuiGraphicsResourceManager
***********************************************************************/

			GuiGraphicsResourceManager::GuiGraphicsResourceManager()
			{
			}

			GuiGraphicsResourceManager::~GuiGraphicsResourceManager()
			{
			}

			vint GuiGraphicsResourceManager::RegisterElementType(const WString& elementTypeName)
			{
				CHECK_ERROR(!elementTypes.Contains(elementTypeName), L"GuiGraphicsResourceManager::RegisterElementType(const WString&)#This element type has already been registered.");
				return elementTypes.Add(elementTypeName);
			}

			void GuiGraphicsResourceManager::RegisterRendererFactory(vint elementType, Ptr<IGuiGraphicsRendererFactory> factory)
			{
				if (rendererFactories.Count() <= elementType)
				{
					rendererFactories.Resize(elementType + 1);
					rendererFactories[elementType] = factory;
				}
				else
				{
					CHECK_ERROR(!rendererFactories[elementType], L"GuiGraphicsResourceManager::RegisterRendererFactory(vint, Ptr<IGuiGraphicsRendererFactory>)#This element type has already been binded a renderer factory.");
					rendererFactories[elementType] = factory;
				}
			}

			IGuiGraphicsRendererFactory* GuiGraphicsResourceManager::GetRendererFactory(vint elementType)
			{
				return rendererFactories.Count() > elementType ? rendererFactories[elementType].Obj() : nullptr;
			}

			IGuiGraphicsResourceManager* guiGraphicsResourceManager = nullptr;

			IGuiGraphicsResourceManager* GetGuiGraphicsResourceManager()
			{
				return guiGraphicsResourceManager;
			}

			void SetGuiGraphicsResourceManager(IGuiGraphicsResourceManager* resourceManager)
			{
				guiGraphicsResourceManager=resourceManager;
			}
		}
	}
}

/***********************************************************************
.\NATIVEWINDOW\GUINATIVEWINDOW.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		const NativeWindowFrameConfig NativeWindowFrameConfig::Default = {};

/***********************************************************************
INativeAutomationService
***********************************************************************/

		class UnavailableAutomationService : public Object, public INativeAutomationService
		{
		public:
			bool Available() override
			{
				return false;
			}

			void Stop() override
			{
			}

			bool CanDumpControlTree() override
			{
				CHECK_FAIL(L"Not Implemented!");
			}

			WString DumpControlTree() override
			{
				CHECK_FAIL(L"Not Implemented!");
			}

			bool CanDumpDomTree() override
			{
				CHECK_FAIL(L"Not Implemented!");
			}

			WString DumpDomTree() override
			{
				CHECK_FAIL(L"Not Implemented!");
			}

			INativeAutomationService::IOCommandAvailability CanRunIOCommands() override
			{
				CHECK_FAIL(L"Not Implemented!");
			}

			WString RunIOCommand(Nullable<WString> windowId, const WString&) override
			{
				CHECK_FAIL(L"Not Implemented!");
			}
		};

		INativeAutomationService* INativeAutomationService::UnavailableService()
		{
			static UnavailableAutomationService service;
			return &service;
		}

/***********************************************************************
INativeWindowListener
***********************************************************************/

		INativeWindowListener::HitTestResult INativeWindowListener::HitTest(NativePoint location)
		{
			return INativeWindowListener::NoDecision;
		}

		void INativeWindowListener::Moving(NativeRect& bounds, bool fixSizeOnly, bool draggingBorder)
		{
		}

		void INativeWindowListener::Moved()
		{
		}

		void INativeWindowListener::DpiChanged(bool preparing)
		{
		}

		void INativeWindowListener::Enabled()
		{
		}

		void INativeWindowListener::Disabled()
		{
		}

		void INativeWindowListener::GotFocus()
		{
		}

		void INativeWindowListener::LostFocus()
		{
		}

		void INativeWindowListener::RenderingAsActivated()
		{
		}

		void INativeWindowListener::RenderingAsDeactivated()
		{
		}

		void INativeWindowListener::Opened()
		{
		}

		void INativeWindowListener::BeforeClosing(bool& cancel)
		{
		}

		void INativeWindowListener::AfterClosing()
		{
		}

		void INativeWindowListener::Closed()
		{
		}

		void INativeWindowListener::Paint()
		{
		}

		void INativeWindowListener::Destroying()
		{
		}

		void INativeWindowListener::Destroyed()
		{
		}

		void INativeWindowListener::LeftButtonDown(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::LeftButtonUp(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::LeftButtonDoubleClick(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::RightButtonDown(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::RightButtonUp(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::RightButtonDoubleClick(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::MiddleButtonDown(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::MiddleButtonUp(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::MiddleButtonDoubleClick(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::HorizontalWheel(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::VerticalWheel(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::MouseMoving(const NativeWindowMouseInfo& info)
		{
		}

		void INativeWindowListener::MouseEntered()
		{
		}

		void INativeWindowListener::MouseLeaved()
		{
		}

		void INativeWindowListener::KeyDown(const NativeWindowKeyInfo& info)
		{
		}

		void INativeWindowListener::KeyUp(const NativeWindowKeyInfo& info)
		{
		}

		void INativeWindowListener::Char(const NativeWindowCharInfo& info)
		{
		}

		bool INativeWindowListener::NeedRefresh()
		{
			return false;
		}

		void INativeWindowListener::ForceRefresh(bool handleFailure, bool& updated, bool& failureByResized, bool& failureByLostDevice)
		{
		}

		void INativeWindowListener::AssignFrameConfig(const NativeWindowFrameConfig& config)
		{
		}

/***********************************************************************
INativeControllerListener
***********************************************************************/

		void INativeControllerListener::GlobalTimer()
		{
		}

		void INativeControllerListener::ClipboardUpdated()
		{
		}

		void INativeControllerListener::GlobalShortcutKeyActivated(vint id)
		{
		}

		void INativeControllerListener::NativeWindowCreated(INativeWindow* window)
		{
		}

		void INativeControllerListener::NativeWindowDestroying(INativeWindow* window)
		{
		}

		void INativeControllerListener::EnvironmentChanged()
		{
		}

/***********************************************************************
Native Window Provider
***********************************************************************/

		class SubstitutableController;
		INativeController* nativeController = nullptr;
		SubstitutableController* substitutableController = nullptr;

		class SubstitutableController
			: public Object
			, public INativeController
			, public INativeServiceSubstitution
		{
		public:
			WString GetExecutablePath() override
			{
				return nativeController->GetExecutablePath();
			}

			// Substitutable Service

			template<typename T, T* (INativeController::* Getter)()>
			struct Substitution
			{
				T*					service = nullptr;
				bool				optional = false;
				bool				requested = false;
				bool				unsubstituted = false;

				void Substitute(T* _service, bool _optional)
				{
					CHECK_ERROR(
						!requested,
						L"The service cannot be substituted because it has been used."
						);
					if (service && !optional && _optional)
					{
						return;
					}
					service = _service;
					optional = _optional;
				}

				void Unsubstitute(T* _service)
				{
					if (service == _service)
					{
						if (requested)
						{
							unsubstituted = true;
						}
						service = nullptr;
					}
				}

				T* GetService()
				{
					CHECK_ERROR(
						!unsubstituted,
						L"The service cannot be used because it has been unsubstituted."
						);
					requested = true;

					auto nativeService = (nativeController->*Getter)();
					if (service && (!nativeService || !optional))
					{
						return service;
					}

					CHECK_ERROR(
						nativeService != nullptr,
						L"Required service does not exist."
						);
					return nativeService;
				}
			};

			// Unsubstitutable Service

			template<typename T, T* (INativeController::* Getter)()>
			T* GetUnsubstitutableService()
			{
				auto nativeService = (nativeController->*Getter)();
				CHECK_ERROR(
					nativeService != nullptr,
					L"Required service does not exist."
				);
				return nativeService;
			}

			// INativeServiceSubstitution and INativeController

#define GET_SUBSTITUTABLE_SERVICE(NAME)														\
			Substitution<																	\
				INative##NAME##Service,														\
				&INativeController::NAME##Service											\
				> substituted##NAME;														\
																							\
			void Substitute(INative##NAME##Service* service, bool optional) override		\
			{																				\
				substituted##NAME.Substitute(service, optional);							\
			}																				\
																							\
			void Unsubstitute(INative##NAME##Service* service) override						\
			{																				\
				substituted##NAME.Unsubstitute(service);									\
			}																				\
																							\
			INative##NAME##Service* NAME##Service() override								\
			{																				\
				return substituted##NAME.GetService();										\
			}																				\

			GUI_SUBSTITUTABLE_SERVICES(GET_SUBSTITUTABLE_SERVICE)
#undef GET_SUBSTITUTABLE_SERVICE

#define GET_UNSUBSTITUTABLE_SERVICE(NAME)													\
			INative##NAME##Service* NAME##Service() override								\
			{																				\
				return GetUnsubstitutableService<											\
					INative##NAME##Service,													\
					&INativeController::NAME##Service										\
					>();																	\
			}																				\

			GUI_UNSUBSTITUTABLE_SERVICES(GET_UNSUBSTITUTABLE_SERVICE)
#undef GET_UNSUBSTITUTABLE_SERVICE
		};

		INativeServiceSubstitution* GetNativeServiceSubstitution()
		{
			return substitutableController;
		}

		INativeController* GetCurrentController()
		{
			return substitutableController;
		}

		void SetNativeController(INativeController* controller)
		{
			nativeController = controller;

			if (nativeController)
			{
				if (!substitutableController)
				{
					substitutableController = new SubstitutableController();
				}
			}
			else
			{
				if (substitutableController)
				{
					delete substitutableController;
					substitutableController = 0;
				}
			}
		}

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

		NativeImageFrameBase::NativeImageFrameBase()
		{
		}

		NativeImageFrameBase::~NativeImageFrameBase()
		{
			// TODO: (enumerable) foreach
			for (vint i = 0; i < caches.Count(); i++)
			{
				caches.Values().Get(i)->OnDetach(this);
			}
		}

		bool NativeImageFrameBase::SetCache(void* key, Ptr<INativeImageFrameCache> cache)
		{
			vint index = caches.Keys().IndexOf(key);
			if (index != -1)
			{
				return false;
			}
			caches.Add(key, cache);
			cache->OnAttach(this);
			return true;
		}

		Ptr<INativeImageFrameCache> NativeImageFrameBase::GetCache(void* key)
		{
			vint index = caches.Keys().IndexOf(key);
			return index == -1 ? nullptr : caches.Values().Get(index);
		}

		Ptr<INativeImageFrameCache> NativeImageFrameBase::RemoveCache(void* key)
		{
			vint index = caches.Keys().IndexOf(key);
			if (index == -1)
			{
				return 0;
			}
			Ptr<INativeImageFrameCache> cache = caches.Values().Get(index);
			cache->OnDetach(this);
			caches.Remove(key);
			return cache;
		}

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

		INativeCursor* GetCursorFromHitTest(INativeWindowListener::HitTestResult hitTestResult, INativeResourceService* resourceService)
		{
			switch (hitTestResult)
			{
			case INativeWindowListener::BorderLeft:
			case INativeWindowListener::BorderRight:
				return resourceService->GetSystemCursor(INativeCursor::SizeWE);
			case INativeWindowListener::BorderTop:
			case INativeWindowListener::BorderBottom:
				return resourceService->GetSystemCursor(INativeCursor::SizeNS);
			case INativeWindowListener::BorderLeftTop:
			case INativeWindowListener::BorderRightBottom:
				return resourceService->GetSystemCursor(INativeCursor::SizeNWSE);
			case INativeWindowListener::BorderRightTop:
			case INativeWindowListener::BorderLeftBottom:
				return resourceService->GetSystemCursor(INativeCursor::SizeNESW);
			default:
				return nullptr;
			}
		}

		void NativeWindowListener_Moving(INativeWindow* window, NativeSize minWindowSize, NativeRect& bounds, bool fixSizeOnly, bool draggingBorder)
		{
			NativeRect oldBounds = window->GetBounds();
			if (bounds.Width() < minWindowSize.x)
			{
				if (fixSizeOnly)
				{
					if (bounds.Width() < minWindowSize.x)
					{
						bounds.x2 = bounds.x1 + minWindowSize.x;
					}
				}
				else if (oldBounds.x1 != bounds.x1)
				{
					bounds.x1 = oldBounds.x2 - minWindowSize.x;
				}
				else if (oldBounds.x2 != bounds.x2)
				{
					bounds.x2 = oldBounds.x1 + minWindowSize.x;
				}
			}
			if (bounds.Height() < minWindowSize.y)
			{
				if (fixSizeOnly)
				{
					if (bounds.Height() < minWindowSize.y)
					{
						bounds.y2 = bounds.y1 + minWindowSize.y;
					}
				}
				else if (oldBounds.y1 != bounds.y1)
				{
					bounds.y1 = oldBounds.y2 - minWindowSize.y;
				}
				else if (oldBounds.y2 != bounds.y2)
				{
					bounds.y2 = oldBounds.y1 + minWindowSize.y;
				}
			}
		}
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\GACGEN\GACGENCONTROLLER.CPP
***********************************************************************/

using namespace vl;
using namespace vl::stream;
using namespace vl::reflection::description;
using namespace vl::presentation;

class GacGenNativeController
	: public Object
	, public INativeController
	, protected INativeCallbackService
	, protected INativeResourceService
	, protected INativeImageService
	, protected INativeInputService
{
public:
	INativeCallbackService* CallbackService() override
	{
		return this;
	}

	INativeResourceService* ResourceService() override
	{
		return this;
	}

	INativeAsyncService* AsyncService() override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	INativeClipboardService* ClipboardService() override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	INativeImageService* ImageService() override
	{
		return this;
	}

	INativeScreenService* ScreenService() override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	INativeWindowService* WindowService() override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	INativeInputService* InputService() override
	{
		return this;
	}

	INativeDialogService* DialogService() override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	INativeAutomationService* AutomationService() override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	WString GetExecutablePath() override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	////////////////////////////////////////////////////////////////////
	// INativeCallbackService
	////////////////////////////////////////////////////////////////////

	bool InstallListener(INativeControllerListener* listener) override
	{
		return true;
	}

	bool UninstallListener(INativeControllerListener* listener) override
	{
		return true;
	}

	INativeCallbackInvoker* Invoker() override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	////////////////////////////////////////////////////////////////////
	// INativeResourceService
	////////////////////////////////////////////////////////////////////

	INativeCursor* GetSystemCursor(INativeCursor::SystemCursorType type) override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	INativeCursor* GetDefaultSystemCursor() override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	FontProperties GetDefaultFont() override
	{
		FontProperties font;
		font.fontFamily = L"GacGen";
		font.size = 12;
		font.bold = false;
		font.italic = false;
		font.underline = false;
		font.strikeline = false;
		font.antialias = false;
		font.verticalAntialias = false;
		return font;
	}

	void SetDefaultFont(const FontProperties& value) override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	void EnumerateFonts(collections::List<WString>& fonts) override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	////////////////////////////////////////////////////////////////////
	// INativeImageService
	////////////////////////////////////////////////////////////////////

	class NativeImage : public Object, public INativeImage
	{
	protected:
		INativeImageService*		imageService;
		MemoryStream				memoryStream;

	public:
		NativeImage(INativeImageService* _imageService, IStream& inputStream)
			: imageService(_imageService)
		{
			CopyStream(inputStream, memoryStream);
		}

		INativeImageService* GetImageService() override
		{
			return imageService;
		}

		FormatType GetFormat() override
		{
			CHECK_FAIL(L"Not implemented!");
		}

		vint GetFrameCount() override
		{
			return 0;
		}

		INativeImageFrame* GetFrame(vint index) override
		{
			CHECK_FAIL(L"Not implemented!");
		}

		void SaveToStream(stream::IStream& imageStream, FormatType formatType) override
		{
			CHECK_ERROR(formatType == FormatType::Unknown, L"Not Implemented!");
			memoryStream.SeekFromBegin(0);
			CopyStream(memoryStream, imageStream);
		}
	};

	Ptr<INativeImage> CreateImageFromFile(const WString& path) override
	{
		FileStream imageStream(path, FileStream::ReadOnly);
		if (!imageStream.IsAvailable()) return nullptr;
		return Ptr(new NativeImage(this, imageStream));
	}

	Ptr<INativeImage> CreateImageFromMemory(void* buffer, vint length) override
	{
		MemoryWrapperStream imageStream(buffer, length);
		return Ptr(new NativeImage(this, imageStream));
	}

	Ptr<INativeImage> CreateImageFromStream(stream::IStream& imageStream) override
	{
		return Ptr(new NativeImage(this, imageStream));
	}

	////////////////////////////////////////////////////////////////////
	// INativeInputService
	////////////////////////////////////////////////////////////////////

	void StartTimer() override
	{
	}

	void StopTimer() override
	{
	}

	bool IsTimerEnabled() override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	bool IsKeyPressing(VKEY code) override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	bool IsKeyToggled(VKEY code) override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	WString GetKeyName(VKEY code) override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	VKEY GetKey(const WString& name) override
	{
		CHECK_FAIL(L"Not implemented!");
	}

	vint RegisterGlobalShortcutKey(bool ctrl, bool shift, bool alt, VKEY key) override
	{
		CHECK_FAIL(L"Not Implemented!");
	}

	bool UnregisterGlobalShortcutKey(vint id) override
	{
		CHECK_FAIL(L"Not Implemented!");
	}
};

extern void GuiApplicationMain();

int SetupGacGenNativeController()
{
	GacGenNativeController controller;
	SetNativeController(&controller);
	GuiApplicationMain();
	SetNativeController(nullptr);
	return 0;
}


/***********************************************************************
.\PLATFORMPROVIDERS\HOSTED\GUIHOSTEDAPPLICATION.CPP
***********************************************************************/

namespace vl::presentation
{
	IGuiHostedApplication* hostedApplication = nullptr;

	IGuiHostedApplication* GetHostedApplication()
	{
		return hostedApplication;
	}

	void SetHostedApplication(IGuiHostedApplication* _hostedApp)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::SetHostedApplication(IGuiHostedApplication*)#"
		if (_hostedApp)
		{
			CHECK_ERROR(!hostedApplication, ERROR_MESSAGE_PREFIX L"IGuiHostedApplication instance already exists during initializing.");
		}
		else
		{
			CHECK_ERROR(hostedApplication, ERROR_MESSAGE_PREFIX L"IGuiHostedApplication instance does not exist during finalizing.");
		}
		hostedApplication = _hostedApp;
#undef ERROR_MESSAGE_PREFIX
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\HOSTED\GUIHOSTEDCONTROLLER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;

/***********************************************************************
GuiHostedController
***********************************************************************/

		NativePoint GuiHostedController::GetPointInClientSpace(NativePoint location)
		{
			auto windowBounds = nativeWindow->GetBounds();
			auto clientBounds = nativeWindow->GetClientBoundsInScreen();
			location.x.value += windowBounds.x1.value - clientBounds.x1.value;
			location.y.value += windowBounds.y1.value - clientBounds.y1.value;
			return location;
		}

		GuiHostedWindow* GuiHostedController::HitTestInClientSpace(NativePoint location)
		{
			auto window = wmManager->HitTest(location);
			return window ? window->id : nullptr;
		}

		void GuiHostedController::UpdateHoveringWindow(Nullable<NativePoint> location)
		{
			if (location)
			{
				hoveringLocation = location.Value();
			}
			hoveringWindow = HitTestInClientSpace(hoveringLocation);
		}

		void GuiHostedController::UpdateEnteringWindow(GuiHostedWindow* window)
		{
			if (enteringWindow != window)
			{
				if (enteringWindow)
				{
					for (auto listener : enteringWindow->listeners)
					{
						listener->MouseLeaved();
					}
				}
				enteringWindow = window;
				if (enteringWindow)
				{
					for (auto listener : enteringWindow->listeners)
					{
						listener->MouseEntered();
					}
				}
			}
		}

/***********************************************************************
GuiHostedController::WindowManager<GuiHostedWindow*>
***********************************************************************/

		void GuiHostedController::OnOpened(hosted_window_manager::Window<GuiHostedWindow*>* window)
		{
			if (!mainWindow || window != &mainWindow->wmWindow)
			{
				for (auto listener : window->id->listeners)
				{
					listener->Opened();
				}
			}
		}

		void GuiHostedController::OnClosed(hosted_window_manager::Window<GuiHostedWindow*>* window)
		{
			for (auto listener : window->id->listeners)
			{
				listener->Closed();
			}
		}

		void GuiHostedController::OnEnabled(hosted_window_manager::Window<GuiHostedWindow*>* window)
		{
			for (auto listener : window->id->listeners)
			{
				listener->Enabled();
			}
		}

		void GuiHostedController::OnDisabled(hosted_window_manager::Window<GuiHostedWindow*>* window)
		{
			for (auto listener : window->id->listeners)
			{
				listener->Disabled();
			}
		}

		void GuiHostedController::OnGotFocus(hosted_window_manager::Window<GuiHostedWindow*>* window)
		{
			window->id->BecomeFocusedWindow();
			for (auto listener : window->id->listeners)
			{
				listener->GotFocus();
			}
		}

		void GuiHostedController::OnLostFocus(hosted_window_manager::Window<GuiHostedWindow*>* window)
		{
			for (auto listener : window->id->listeners)
			{
				listener->LostFocus();
			}
		}

		void GuiHostedController::OnActivated(hosted_window_manager::Window<GuiHostedWindow*>* window)
		{
			for (auto listener : window->id->listeners)
			{
				listener->RenderingAsActivated();
			}
		}

		void GuiHostedController::OnDeactivated(hosted_window_manager::Window<GuiHostedWindow*>* window)
		{
			for (auto listener : window->id->listeners)
			{
				listener->RenderingAsDeactivated();
			}
		}

/***********************************************************************
GuiHostedController::INativeWindowListener
***********************************************************************/

		INativeWindowListener::HitTestResult GuiHostedController::HitTest(NativePoint location)
		{
			if (mainWindow && mainWindow->IsEnabled())
			{
				auto point = GetPointInClientSpace(location);
				auto window = HitTestInClientSpace(point);
				if (window == mainWindow)
				{
					return PerformHitTest(From(mainWindow->listeners), point);
				}
			}
			return INativeWindowListener::HitTestResult::NoDecision;
		}

		void GuiHostedController::Moving(NativeRect& bounds, bool fixSizeOnly, bool draggingBorder)
		{
			if (mainWindow)
			{
				auto windowBounds = nativeWindow->GetBounds();
				NativeRect mainBounds;
				mainBounds.x1 = bounds.x1 - windowBounds.x1;
				mainBounds.y1 = bounds.y1 - windowBounds.y1;
				mainBounds.x2 = bounds.x2 - windowBounds.x1;
				mainBounds.y2 = bounds.y2 - windowBounds.y1;

				for (auto listener : mainWindow->listeners)
				{
					listener->Moving(mainBounds, fixSizeOnly, draggingBorder);
				}

				bounds.x1 = mainBounds.x1 + windowBounds.x1;
				bounds.y1 = mainBounds.y1 + windowBounds.y1;
				bounds.x2 = mainBounds.x2 + windowBounds.x1;
				bounds.y2 = mainBounds.y2 + windowBounds.y1;
			}
		}

		void GuiHostedController::Moved()
		{
			if (mainWindow)
			{
				auto size = mainWindow->GetBounds().GetSize();
				auto clientSize = nativeWindow->GetClientSize();
				if (size != clientSize)
				{
					mainWindow->SetBounds({ {},clientSize });
				}

				for (auto listener : mainWindow->listeners)
				{
					listener->Moved();
				}
			}
		}

		void GuiHostedController::DpiChanged(bool preparing)
		{
			if (!preparing)
			{
				hostedResourceManager->nativeManager->RecreateRenderTarget(nativeWindow);
				wmManager->needRefresh = true;
			}

			for (auto hostedWindow : createdWindows)
			{
				for (auto listener : hostedWindow->listeners)
				{
					listener->DpiChanged(preparing);
				}
			}
		}

		void GuiHostedController::GotFocus()
		{
			if (lastFocusedWindow)
			{
				lastFocusedWindow->wmWindow.Activate();
				lastFocusedWindow = nullptr;
			}
			else if (mainWindow)
			{
				mainWindow->wmWindow.Activate();
			}
		}

		void GuiHostedController::Opened()
		{
			if (mainWindow)
			{
				for (auto listener : mainWindow->wmWindow.id->listeners)
				{
					listener->Opened();
				}
			}
		}

		void GuiHostedController::LostFocus()
		{
			lastFocusedWindow = wmManager->activeWindow ? wmManager->activeWindow->id : nullptr;
			while (wmManager->activeWindow)
			{
				wmManager->activeWindow->Deactivate();
			}
		}

		void GuiHostedController::BeforeClosing(bool& cancel)
		{
			if (mainWindow)
			{
				for (auto listener : mainWindow->listeners)
				{
					listener->BeforeClosing(cancel);
					if (cancel) return;
				}
			}
		}

		void GuiHostedController::AfterClosing()
		{
			if (mainWindow)
			{
				for (auto listener : mainWindow->listeners)
				{
					listener->AfterClosing();
				}
			}
		}

		void GuiHostedController::Paint()
		{
		}

/***********************************************************************
GuiHostedController::INativeWindowListener (GetSelectedWindow)
***********************************************************************/

		GuiHostedWindow* GuiHostedController::GetSelectedWindow_MouseDown(const NativeWindowMouseInfo& info)
		{
			if (!capturingWindow)
			{
				SortedList<GuiHostedWindow*> survivedPopups;
				auto current = hoveringWindow;
				while (current)
				{
					if (current->IsVisible() && current->GetWindowMode() != INativeWindow::Normal)
					{
						survivedPopups.Add(current);
					}
					current = current->wmWindow.parent ? current->wmWindow.parent->id : nullptr;
				}

				List<GuiHostedWindow*> closingPopups;
				CopyFrom(
					closingPopups,
					From(wmManager->ordinaryWindowsInOrder)
						.Concat(wmManager->topMostedWindowsInOrder)
						.Select([](auto window) { return window->id; })
						.Where([&](auto window) { return window->GetWindowMode() != INativeWindow::Normal && !survivedPopups.Contains(window); })
					);
				for (auto popupWindow : closingPopups)
				{
					popupWindow->Hide(false);
				}
			}

			auto selectedWindow = capturingWindow ? capturingWindow : hoveringWindow;
			return selectedWindow;
		}

		GuiHostedWindow* GuiHostedController::GetSelectedWindow_MouseMoving(const NativeWindowMouseInfo& info)
		{
			UpdateHoveringWindow({ { info.x,info.y } });
			auto selectedWindow = capturingWindow ? capturingWindow : hoveringWindow;
			UpdateEnteringWindow(selectedWindow);
			return selectedWindow;
		}

		GuiHostedWindow* GuiHostedController::GetSelectedWindow_Other(const NativeWindowMouseInfo& info)
		{
			auto selectedWindow = capturingWindow ? capturingWindow : hoveringWindow;
			return selectedWindow;
		}

/***********************************************************************
GuiHostedController::INativeWindowListener (PreAction)
***********************************************************************/

		void GuiHostedController::PreAction_LeftButtonDown(const NativeWindowMouseInfo& info)
		{
			PreAction_MouseDown(info);

			if (!capturingWindow && !wmWindow && hoveringWindow && hoveringWindow != mainWindow && hoveringWindow->IsEnabled())
			{
				auto x = info.x.value - hoveringWindow->wmWindow.bounds.x1.value;
				auto y = info.y.value - hoveringWindow->wmWindow.bounds.y1.value;
				auto hitTestResult = PerformHitTest(From(hoveringWindow->listeners), { {x},{y} });

				switch (hitTestResult)
				{
#define HANDLE_HIT_TEST_RESULT(NAME)\
				case INativeWindowListener::NAME:				\
					wmOperation = WindowManagerOperation::NAME;	\
					break;										\

				HANDLE_HIT_TEST_RESULT(Title)
				HANDLE_HIT_TEST_RESULT(BorderLeft)
				HANDLE_HIT_TEST_RESULT(BorderRight)
				HANDLE_HIT_TEST_RESULT(BorderTop)
				HANDLE_HIT_TEST_RESULT(BorderBottom)
				HANDLE_HIT_TEST_RESULT(BorderLeftTop)
				HANDLE_HIT_TEST_RESULT(BorderRightBottom)
				HANDLE_HIT_TEST_RESULT(BorderRightTop)
				HANDLE_HIT_TEST_RESULT(BorderLeftBottom)
				default:;

#undef HANDLE_HIT_TEST_RESULT
				}

				switch (wmOperation)
				{
				case WindowManagerOperation::None:
					return;
				case WindowManagerOperation::Title:
					if (!hoveringWindow->GetTitleBar())
					{
						wmOperation = WindowManagerOperation::None;
						return;
					}
					break;
				default:
					if (!hoveringWindow->GetSizeBox())
					{
						wmOperation = WindowManagerOperation::None;
						return;
					}
				}

				wmWindow = hoveringWindow;
				nativeWindow->RequireCapture();

				switch (wmOperation)
				{
				case WindowManagerOperation::Title:
				case WindowManagerOperation::BorderLeft:
				case WindowManagerOperation::BorderLeftTop:
				case WindowManagerOperation::BorderLeftBottom:
					wmRelative.x.value = x;
					break;
				case WindowManagerOperation::BorderTop:
				case WindowManagerOperation::BorderBottom:
					wmRelative.x.value = wmWindow->wmWindow.bounds.Width().value / 2;
					break;
				case WindowManagerOperation::BorderRight:
				case WindowManagerOperation::BorderRightTop:
				case WindowManagerOperation::BorderRightBottom:
					wmRelative.x.value = wmWindow->wmWindow.bounds.Width().value - x;
					break;
				default:;
				}

				switch (wmOperation)
				{
				case WindowManagerOperation::Title:
				case WindowManagerOperation::BorderTop:
				case WindowManagerOperation::BorderLeftTop:
				case WindowManagerOperation::BorderRightTop:
					wmRelative.y.value = y;
					break;
				case WindowManagerOperation::BorderLeft:
				case WindowManagerOperation::BorderRight:
					wmRelative.y.value = wmWindow->wmWindow.bounds.Height().value / 2;
					break;
				case WindowManagerOperation::BorderBottom:
				case WindowManagerOperation::BorderLeftBottom:
				case WindowManagerOperation::BorderRightBottom:
					wmRelative.y.value = wmWindow->wmWindow.bounds.Height().value - y;
					break;
				default:;
				}
			}
		}

		void GuiHostedController::PreAction_MouseDown(const NativeWindowMouseInfo& info)
		{
			if (!capturingWindow && !wmWindow && hoveringWindow && hoveringWindow->IsEnabled() && hoveringWindow->IsEnabledActivate())
			{
				hoveringWindow->SetActivate();
			}
		}

		void GuiHostedController::PreAction_MouseMoving(const NativeWindowMouseInfo& info)
		{
			if (!capturingWindow && !wmWindow && hoveringWindow && hoveringWindow != mainWindow && hoveringWindow->IsEnabled() && hoveringWindow->GetSizeBox())
			{
				auto x = info.x.value - hoveringWindow->wmWindow.bounds.x1.value;
				auto y = info.y.value - hoveringWindow->wmWindow.bounds.y1.value;
				auto hitTestResult = PerformHitTest(From(hoveringWindow->listeners), { {x},{y} });
				auto cursor = GetCursorFromHitTest(hitTestResult, ResourceService());
				if (cursor == nullptr)
				{
					cursor = hoveringWindow->GetWindowCursor();
				}
				nativeWindow->SetWindowCursor(cursor);
			}

			if (wmWindow)
			{
				auto oldBounds = wmWindow->wmWindow.bounds;
				auto newBounds = oldBounds;
				vint mouseX = info.x.value;
				vint mouseY = info.y.value;
				vint displayX = mainWindow->wmWindow.bounds.Width().value;
				vint displayY = mainWindow->wmWindow.bounds.Height().value;

				if (mouseX < 0)
				{
					mouseX = 0;
				}
				else if (mouseX >= displayX)
				{
					mouseX = displayX - 1;
				}

				if (mouseY < 0)
				{
					mouseY = 0;
				}
				else if (mouseY >= displayY)
				{
					mouseY = displayY - 1;
				}

				if (wmOperation == WindowManagerOperation::Title)
				{
					newBounds = {
						{
							{mouseX - wmRelative.x.value},
							{mouseY - wmRelative.y.value}
						},
						oldBounds.GetSize()
					};
				}
				else
				{
					switch (wmOperation)
					{
					case WindowManagerOperation::BorderLeft:
					case WindowManagerOperation::BorderLeftTop:
					case WindowManagerOperation::BorderLeftBottom:
						newBounds.x1.value = mouseX - wmRelative.x.value;
						break;
					case WindowManagerOperation::BorderRight:
					case WindowManagerOperation::BorderRightTop:
					case WindowManagerOperation::BorderRightBottom:
						newBounds.x2.value = mouseX + wmRelative.x.value;
						break;
					default:;
					}

					switch (wmOperation)
					{
					case WindowManagerOperation::BorderTop:
					case WindowManagerOperation::BorderLeftTop:
					case WindowManagerOperation::BorderRightTop:
						newBounds.y1.value = mouseY - wmRelative.y.value;
						break;
					case WindowManagerOperation::BorderBottom:
					case WindowManagerOperation::BorderLeftBottom:
					case WindowManagerOperation::BorderRightBottom:
						newBounds.y2.value = mouseY + wmRelative.y.value;
						break;
					default:;
					}
				}

				for (auto listener : wmWindow->listeners)
				{
					listener->Moving(newBounds, false, wmOperation != WindowManagerOperation::Title);
				}

				wmWindow->wmWindow.SetBounds(newBounds);

				for (auto listener : wmWindow->listeners)
				{
					listener->Moved();
				}
			}
		}

		void GuiHostedController::PreAction_Other(const NativeWindowMouseInfo& info)
		{
		}

/***********************************************************************
GuiHostedController::INativeWindowListener (PostAction)
***********************************************************************/

		void GuiHostedController::PostAction_LeftButtonUp(GuiHostedWindow* selectedWindow, const NativeWindowMouseInfo& info)
		{
			if (!capturingWindow && !wmWindow && selectedWindow && selectedWindow != mainWindow && selectedWindow->IsEnabled())
			{
				auto x = info.x.value - selectedWindow->wmWindow.bounds.x1.value;
				auto y = info.y.value - selectedWindow->wmWindow.bounds.y1.value;
				auto hitTestResult = PerformHitTest(From(selectedWindow->listeners), { {x},{y} });
				if (hitTestResult == INativeWindowListener::ButtonClose)
				{
					selectedWindow->Hide(true);
				}
			}

			if (wmWindow)
			{
				wmWindow = nullptr;
				wmOperation = WindowManagerOperation::None;
				nativeWindow->ReleaseCapture();
			}
		}

		void GuiHostedController::PostAction_Other(GuiHostedWindow* selectedWindow, const NativeWindowMouseInfo& info)
		{
		}

/***********************************************************************
GuiHostedController::INativeWindowListener (Template)
***********************************************************************/


		template<
			void (GuiHostedController::* PreAction)(const NativeWindowMouseInfo&),
			GuiHostedWindow*(GuiHostedController::* GetSelectedWindow)(const NativeWindowMouseInfo&),
			void (GuiHostedController::* PostAction)(GuiHostedWindow*, const NativeWindowMouseInfo&),
			void (INativeWindowListener::* Callback)(const NativeWindowMouseInfo&)
		>
		void GuiHostedController::HandleMouseCallback(const NativeWindowMouseInfo& info)
		{
			(this->*PreAction)(info);
			auto postActionWindow = hoveringWindow;
			if (!wmWindow)
			{
				if (auto selectedWindow = (this->*GetSelectedWindow)(info))
				{
					postActionWindow = selectedWindow;
					if (!selectedWindow->IsEnabled()) return;
					auto adjustedInfo = info;
					adjustedInfo.x.value -= selectedWindow->wmWindow.bounds.x1.value;
					adjustedInfo.y.value -= selectedWindow->wmWindow.bounds.y1.value;
					for (auto listener : selectedWindow->listeners)
					{
						(listener->*Callback)(adjustedInfo);
					}
				}
			}
			(this->*PostAction)(postActionWindow, info);
		}

		template<
			typename TInfo,
			void (INativeWindowListener::* Callback)(const TInfo&)
		>
		void GuiHostedController::HandleKeyboardCallback(const TInfo& info)
		{
			if (!wmWindow && !wmManager->activeWindow && mainWindow)
			{
				mainWindow->wmWindow.Activate();
			}

			if (wmManager->activeWindow && !wmWindow)
			{
				auto hostedWindow = wmManager->activeWindow->id;
				for (auto listener : hostedWindow->listeners)
				{
					(listener->*Callback)(info);
				}
			}
		}

/***********************************************************************
GuiHostedController::INativeWindowListener (IO Event Handling)
***********************************************************************/

#define IMPLEMENT_MOUSE_CALLBACK(NAME, PREACTION, POLICY, POSTACTION)					\
		void GuiHostedController::NAME(const NativeWindowMouseInfo& info)				\
		{																				\
			HandleMouseCallback<														\
				&GuiHostedController::PreAction_##PREACTION,							\
				&GuiHostedController::GetSelectedWindow_##POLICY,						\
				&GuiHostedController::PostAction_##POSTACTION,							\
				&INativeWindowListener::NAME											\
			>(info);																	\
		}																				\

		IMPLEMENT_MOUSE_CALLBACK(LeftButtonDown,			LeftButtonDown,	MouseDown,		Other			)
		IMPLEMENT_MOUSE_CALLBACK(LeftButtonUp,				Other,			Other,			LeftButtonUp	)
		IMPLEMENT_MOUSE_CALLBACK(LeftButtonDoubleClick,		Other,			Other,			Other			)
		IMPLEMENT_MOUSE_CALLBACK(RightButtonDown,			MouseDown,		MouseDown,		Other			)
		IMPLEMENT_MOUSE_CALLBACK(RightButtonUp,				Other,			Other,			Other			)
		IMPLEMENT_MOUSE_CALLBACK(RightButtonDoubleClick,	Other,			Other,			Other			)
		IMPLEMENT_MOUSE_CALLBACK(MiddleButtonDown,			MouseDown,		MouseDown,		Other			)
		IMPLEMENT_MOUSE_CALLBACK(MiddleButtonUp,			Other,			Other,			Other			)
		IMPLEMENT_MOUSE_CALLBACK(MiddleButtonDoubleClick,	Other,			Other,			Other			)
		IMPLEMENT_MOUSE_CALLBACK(HorizontalWheel,			Other,			Other,			Other			)
		IMPLEMENT_MOUSE_CALLBACK(VerticalWheel,				Other,			Other,			Other			)
		IMPLEMENT_MOUSE_CALLBACK(MouseMoving,				MouseMoving,	MouseMoving,	Other			)

#undef IMPLEMENT_MOUSE_CALLBACK

		void GuiHostedController::MouseEntered()
		{
		}

		void GuiHostedController::MouseLeaved()
		{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::GuiHostedController::MouseLeaved()#"
			UpdateEnteringWindow(nullptr);
#undef ERROR_MESSAGE_PREFIX
		}

#define IMPLEMENT_KEY_CALLBACK(NAME, TYPE)										\
		void GuiHostedController::NAME(const NativeWindow##TYPE##Info& info)	\
		{																		\
			HandleKeyboardCallback<												\
				NativeWindow##TYPE##Info,										\
				&INativeWindowListener::NAME									\
			>(info);															\
		}																		\

		IMPLEMENT_KEY_CALLBACK(KeyDown, Key)
		IMPLEMENT_KEY_CALLBACK(KeyUp, Key)
		IMPLEMENT_KEY_CALLBACK(Char, Char)

#undef IMPLEMENT_KEY_CALLBACK

/***********************************************************************
GuiHostedController::INativeControllerListener
***********************************************************************/

		void GuiHostedController::GlobalTimer()
		{
			callbackService.InvokeGlobalTimer();

			if (hostedResourceManager && nativeWindow && nativeWindow->IsVisible())
			{
				auto renderTarget = hostedResourceManager->nativeManager->GetRenderTarget(nativeWindow);
				if (renderTarget->IsInHostedRendering())
				{
					return;
				}

				for (auto visibleWindow : From(wmManager->ordinaryWindowsInOrder).Concat(wmManager->topMostedWindowsInOrder))
				{
					for (auto listener : visibleWindow->id->listeners)
					{
						if (listener->NeedRefresh())
						{
							wmManager->needRefresh = true;
							goto NEED_REFRESH;
						}
					}
				}

				if (!wmManager->needRefresh && !windowsUpdatedInLastFrame)
				{
					if (!idleNotifiedSinceLastRendering)
					{
						idleNotifiedSinceLastRendering = true;
						renderTarget->HostedRenderingIdle();
					}
					return;
				}

			NEED_REFRESH:
				wmManager->needRefresh = false;
				windowsUpdatedInLastFrame = false;
				idleNotifiedSinceLastRendering = false;

				while (true)
				{
					renderTarget->StartHostedRendering();
					bool failureByResized = false;
					bool failureByLostDevice = false;

					auto forceRefreshWindows = [&](List<hosted_window_manager::Window<GuiHostedWindow*>*>& windows)
					{
						// TODO: (enumerable) foreach:reversed
						for (vint i = windows.Count() - 1; i >= 0; i--)
						{
							auto hostedWindow = windows[i]->id;
							for (auto listener : hostedWindow->listeners)
							{
								bool updated = false;
								listener->ForceRefresh(false, updated, failureByResized, failureByLostDevice);
								windowsUpdatedInLastFrame |= updated;
								if (failureByResized || failureByLostDevice)
								{
									return false;
								}
							}
						}
						return true;
					};

					if (!forceRefreshWindows(wmManager->ordinaryWindowsInOrder)) goto STOP_RENDERING;
					if (!forceRefreshWindows(wmManager->topMostedWindowsInOrder)) goto STOP_RENDERING;

				STOP_RENDERING:
					switch (renderTarget->StopHostedRendering())
					{
					case elements::RenderTargetFailure::LostDevice:
						failureByLostDevice = true;
						break;
					case elements::RenderTargetFailure::ResizeWhileRendering:
						failureByResized = true;
						break;
					default:;
					}

					if (failureByLostDevice)
					{
						hostedResourceManager->nativeManager->RecreateRenderTarget(nativeWindow);
						wmManager->needRefresh = true;
					}
					else if (failureByResized)
					{
						hostedResourceManager->nativeManager->ResizeRenderTarget(nativeWindow);
						wmManager->needRefresh = true;
					}
					else
					{
						nativeWindow->RedrawContent();
						break;
					}
				}
			}
		}

		void GuiHostedController::ClipboardUpdated()
		{
			callbackService.InvokeClipboardUpdated();
		}

		void GuiHostedController::GlobalShortcutKeyActivated(vint id)
		{
			callbackService.InvokeGlobalShortcutKeyActivated(id);
		}

		void GuiHostedController::NativeWindowDestroying(INativeWindow* window)
		{
			if (nativeWindow == window)
			{
				DestroyHostedWindowsAfterRunning();
				nativeWindow->UninstallListener(this);
				nativeWindow = nullptr;
			}
		}

/***********************************************************************
GuiHostedController::INativeAsyncService
***********************************************************************/

		bool GuiHostedController::IsInMainThread(INativeWindow* window)
		{
			return nativeController->AsyncService()->IsInMainThread(nativeWindow);
		}

		void GuiHostedController::InvokeAsync(const Func<void()>& proc)
		{
			return nativeController->AsyncService()->InvokeAsync(proc);
		}

		void GuiHostedController::InvokeInMainThread(INativeWindow* window, const Func<void()>& proc)
		{
			return nativeController->AsyncService()->InvokeInMainThread(nativeWindow, proc);
		}

		bool GuiHostedController::InvokeInMainThreadAndWait(INativeWindow* window, const Func<void()>& proc, vint milliseconds)
		{
			return nativeController->AsyncService()->InvokeInMainThreadAndWait(nativeWindow, proc, milliseconds);
		}

		Ptr<INativeDelay> GuiHostedController::DelayExecute(const Func<void()>& proc, vint milliseconds)
		{
			return nativeController->AsyncService()->DelayExecute(proc, milliseconds);
		}

		Ptr<INativeDelay> GuiHostedController::DelayExecuteInMainThread(const Func<void()>& proc, vint milliseconds)
		{
			return nativeController->AsyncService()->DelayExecuteInMainThread(proc, milliseconds);
		}

/***********************************************************************
GuiHostedController::INativeScreenService
***********************************************************************/

		vint GuiHostedController::GetScreenCount()
		{
			return 1;
		}

		INativeScreen* GuiHostedController::GetScreen(vint index)
		{
			CHECK_ERROR(index == 0, L"vl::presentation::GuiHostedController::GetScreen(vint)#Index out of range.");
			return this;
		}

		INativeScreen* GuiHostedController::GetScreen(INativeWindow* window)
		{
			return this;
		}

/***********************************************************************
GuiHostedController::INativeScreen
***********************************************************************/

		NativeRect GuiHostedController::GetBounds()
		{
			if (nativeWindow->IsCustomFrameModeEnabled())
			{
				return { {},nativeWindow->GetBounds().GetSize() };
			}
			else
			{
				return { {},nativeWindow->GetClientSize() };
			}
		}

		NativeRect GuiHostedController::GetClientBounds()
		{
			return { {},nativeWindow->GetClientSize() };
		}

		WString GuiHostedController::GetName()
		{
			return WString::Unmanaged(L"GacUI Virtual Screen");
		}

		bool GuiHostedController::IsPrimary()
		{
			return true;
		}

		double GuiHostedController::GetScalingX()
		{
			return nativeController->ScreenService()->GetScreen(nativeWindow)->GetScalingX();
		}

		double GuiHostedController::GetScalingY()
		{
			return nativeController->ScreenService()->GetScreen(nativeWindow)->GetScalingY();
		}

/***********************************************************************
GuiHostedController::INativeWindowService
***********************************************************************/

		const NativeWindowFrameConfig& GuiHostedController::GetMainWindowFrameConfig()
		{
			return nativeController->WindowService()->GetMainWindowFrameConfig();
		}

		const NativeWindowFrameConfig& GuiHostedController::GetNonMainWindowFrameConfig()
		{
			static const NativeWindowFrameConfig config = {
				.MaximizedBoxOption = BoolOption::AlwaysFalse,
				.MinimizedBoxOption = BoolOption::AlwaysFalse,
				.CustomFrameEnabled = BoolOption::AlwaysTrue,
			};
			return config;
		}

		INativeWindow* GuiHostedController::CreateNativeWindow(INativeWindow::WindowMode windowMode)
		{
			auto hostedWindow = Ptr(new GuiHostedWindow(this, windowMode));
			createdWindows.Add(hostedWindow);
			wmManager->RegisterWindow(&hostedWindow->wmWindow);

			callbackService.InvokeNativeWindowCreated(hostedWindow.Obj());
			if (mainWindow)
			{
				hostedWindow->BecomeNonMainWindow();
			}
			return hostedWindow.Obj();
		}

		void GuiHostedController::DestroyNativeWindow(INativeWindow* window)
		{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::GuiHostedController::DestroyNativeWindow(INativeWindow*)#"
			auto hostedWindow = dynamic_cast<GuiHostedWindow*>(window);
			CHECK_ERROR(hostedWindow, ERROR_MESSAGE_PREFIX L"The window is not created by GuiHostedController.");
			vint index = createdWindows.IndexOf(hostedWindow);
			CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"The window has been destroyed.");

			if (hostedWindow == enteringWindow) enteringWindow = nullptr;
			if (hostedWindow == hoveringWindow) hoveringWindow = nullptr;
			if (hostedWindow == lastFocusedWindow) enteringWindow = nullptr;
			if (hostedWindow == capturingWindow)
			{
				capturingWindow->ReleaseCapture();
			}
			if (hostedWindow == wmWindow)
			{
				wmOperation = WindowManagerOperation::None;
				wmWindow = nullptr;
				nativeWindow->ReleaseCapture();
			}

			for (auto listener : hostedWindow->listeners)
			{
				listener->Destroying();
			}

			callbackService.InvokeNativeWindowDestroying(hostedWindow);
			wmManager->UnregisterWindow(&hostedWindow->wmWindow);
			createdWindows.RemoveAt(index);

			UpdateHoveringWindow({});
#undef ERROR_MESSAGE_PREFIX
		}

		INativeWindow* GuiHostedController::GetMainWindow()
		{
			return mainWindow;
		}

		INativeWindow* GuiHostedController::GetWindow(NativePoint location)
		{
			auto wmWindow = wmManager->HitTest(location);
			return wmWindow ? wmWindow->id : nullptr;
		}

		void GuiHostedController::SettingHostedWindowsBeforeRunning()
		{
			if (nativeWindow)
			{
				for (auto window : createdWindows)
				{
					if (window == mainWindow)
					{
						window->BecomeMainWindow();
					}
					else
					{
						window->BecomeNonMainWindow();
					}
				}

				if (auto screen = nativeController->ScreenService()->GetScreen(nativeWindow))
				{
					auto screenBounds = screen->GetClientBounds();
					auto windowSize = nativeWindow->GetBounds().GetSize();
					nativeWindow->SetBounds({
						{
							screenBounds.Left() + (screenBounds.Width() - windowSize.x) / 2,
							screenBounds.Top() + (screenBounds.Height() - windowSize.y) / 2
						},
						windowSize
						});
				}

				wmManager->Start(&mainWindow->wmWindow);
			}
		}

		void GuiHostedController::DestroyHostedWindowsAfterRunning()
		{
			if (nativeWindow)
			{
				if (wmManager->mainWindow)
				{
					wmManager->Stop();
				}

				// TODO: (enumerable) foreach:indexed(alterable(reversed))
				for (vint i = createdWindows.Count() - 1; i >= 0; i--)
				{
					auto hostedWindow = createdWindows[i];
					if (hostedWindow != mainWindow)
					{
						DestroyNativeWindow(hostedWindow.Obj());
					}
				}

				if (mainWindow)
				{
					DestroyNativeWindow(mainWindow);
					mainWindow = nullptr;
				}
			}
		}

		namespace GuiHostedController_UnitTestHelper
		{
			static bool exceptionOccuredUnderUnitTestReleaseMode = false;

			bool ExceptionOccuredUnderUnitTestReleaseMode()
			{
				return exceptionOccuredUnderUnitTestReleaseMode;
			}
		}

		void GuiHostedController::Run(INativeWindow* window)
		{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::GuiHostedController::Run(INativeWindow*)#"
			GuiHostedController_UnitTestHelper::exceptionOccuredUnderUnitTestReleaseMode = false;
			CHECK_ERROR(!mainWindow, ERROR_MESSAGE_PREFIX L"This function has been called.");
			auto hostedWindow = dynamic_cast<GuiHostedWindow*>(window);
			CHECK_ERROR(hostedWindow, ERROR_MESSAGE_PREFIX L"The window is not created by GuiHostedController.");
			mainWindow = hostedWindow;

			SettingHostedWindowsBeforeRunning();
			wmManager->needRefresh = true;
			if (unittest::UnitTest::GetFailureMode() == unittest::UnitTest::FailureMode::NotRunning || unittest::UnitTest::GetFailureMode() == unittest::UnitTest::FailureMode::Debug)
			{
				nativeController->WindowService()->Run(nativeWindow);
			}
			else
			{
				try
				{
					nativeController->WindowService()->Run(nativeWindow);
				}
				catch (const Exception& e)
				{
					(void)e;
					if (unittest::UnitTest::GetFailureMode() == unittest::UnitTest::FailureMode::Release)
					{
						GuiHostedController_UnitTestHelper::exceptionOccuredUnderUnitTestReleaseMode = true;
						unittest::UnitTest::PrintMessage(e.Message(), unittest::UnitTest::MessageKind::Error);
					}
					else
					{
						DestroyHostedWindowsAfterRunning();
						throw;
					}
				}
				catch (const Error& e)
				{
					(void)e;
					if (unittest::UnitTest::GetFailureMode() == unittest::UnitTest::FailureMode::Release)
					{
						GuiHostedController_UnitTestHelper::exceptionOccuredUnderUnitTestReleaseMode = true;
						unittest::UnitTest::PrintMessage(e.Description(), unittest::UnitTest::MessageKind::Error);
					}
					else
					{
						DestroyHostedWindowsAfterRunning();
						throw;
					}
				}
				catch (const unittest::UnitTestAssertError& e)
				{
					(void)e;
					if (unittest::UnitTest::GetFailureMode() == unittest::UnitTest::FailureMode::Release)
					{
						GuiHostedController_UnitTestHelper::exceptionOccuredUnderUnitTestReleaseMode = true;
						unittest::UnitTest::PrintMessage(e.message, unittest::UnitTest::MessageKind::Error);
					}
					else
					{
						DestroyHostedWindowsAfterRunning();
						throw;
					}
				}
				catch (...)
				{
					if (unittest::UnitTest::GetFailureMode() != unittest::UnitTest::FailureMode::Release)
					{
						GuiHostedController_UnitTestHelper::exceptionOccuredUnderUnitTestReleaseMode = true;
						unittest::UnitTest::PrintMessage(WString::Unmanaged(L"Runtime exception occurred!"), unittest::UnitTest::MessageKind::Error);
						DestroyHostedWindowsAfterRunning();
						throw;
					}
				}
			}
			CHECK_ERROR((nativeWindow == nullptr) == (mainWindow == nullptr), ERROR_MESSAGE_PREFIX L"Hosted windows should have been destroyed if the native windows is destroyed.");
			DestroyHostedWindowsAfterRunning();
#undef ERROR_MESSAGE_PREFIX
		}

		bool GuiHostedController::RunOneCycle()
		{
			return nativeController->WindowService()->RunOneCycle();
		}

/***********************************************************************
GuiHostedController::IGuiHostedApplication
***********************************************************************/

		INativeWindow* GuiHostedController::GetNativeWindowHost()
		{
			return nativeWindow;
		}

		INativeController* GuiHostedController::GetNativeController()
		{
			return nativeController;
		}

/***********************************************************************
GuiHostedController
***********************************************************************/

		GuiHostedController::GuiHostedController(INativeController* _nativeController)
			: nativeController(_nativeController)
		{
			wmManager = this;
			nativeController->CallbackService()->InstallListener(this);
		}

		GuiHostedController::~GuiHostedController()
		{
		}

		IGuiHostedApplication* GuiHostedController::GetHostedApplication()
		{
			return this;
		}

		void GuiHostedController::Initialize()
		{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::GuiHostedController()::Initialize()#"
			CHECK_ERROR(!nativeWindow, ERROR_MESSAGE_PREFIX L"Initialize() has been called");
			CHECK_ERROR(!nativeWindowDestroyed, ERROR_MESSAGE_PREFIX L"Finalize() has been called.");

			nativeController->CallbackService()->InstallListener(this);
			nativeWindow = nativeController->WindowService()->CreateNativeWindow(INativeWindow::WindowMode::Normal);
			nativeWindow->InstallListener(this);
#undef ERROR_MESSAGE_PREFIX
		}

		void GuiHostedController::Finalize()
		{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::GuiHostedController()::Finalize()#"
			CHECK_ERROR(!nativeWindowDestroyed, ERROR_MESSAGE_PREFIX L"Finalize() has been called.");

			if (nativeWindow)
			{
				nativeController->WindowService()->DestroyNativeWindow(nativeWindow);
			}
			nativeController->CallbackService()->UninstallListener(this);
			nativeWindowDestroyed = true;

#undef ERROR_MESSAGE_PREFIX
		}

		void GuiHostedController::RequestRefresh()
		{
			wmManager->needRefresh = true;
		}

/***********************************************************************
GuiHostedController::INativeController
***********************************************************************/

		INativeCallbackService* GuiHostedController::CallbackService()
		{
			return &callbackService;
		}

		INativeResourceService* GuiHostedController::ResourceService()
		{
			return nativeController->ResourceService();
		}

		INativeAsyncService* GuiHostedController::AsyncService()
		{
			return this;
		}

		INativeClipboardService* GuiHostedController::ClipboardService()
		{
			return nativeController->ClipboardService();
		}

		INativeImageService* GuiHostedController::ImageService()
		{
			return nativeController->ImageService();
		}

		INativeInputService* GuiHostedController::InputService()
		{
			return nativeController->InputService();
		}

		INativeDialogService* GuiHostedController::DialogService()
		{
			// Use FakeDialogServiceBase
			return nullptr;
		}

		INativeAutomationService* GuiHostedController::AutomationService()
		{
			// Use INativeAutomationService::UnavailableService
			return nullptr;
		}

		WString GuiHostedController::GetExecutablePath()
		{
			return nativeController->GetExecutablePath();
		}
		
		INativeScreenService* GuiHostedController::ScreenService()
		{
			return this;
		}

		INativeWindowService* GuiHostedController::WindowService()
		{
			return this;
		}
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\HOSTED\GUIHOSTEDGRAPHICS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace elements
		{

/***********************************************************************
GuiHostedGraphicsResourceManager
***********************************************************************/
			
			GuiHostedGraphicsResourceManager::GuiHostedGraphicsResourceManager(GuiHostedController* _hostedController, IGuiGraphicsResourceManager* _nativeManager)
				: hostedController(_hostedController)
				, nativeManager(_nativeManager)
			{
				CHECK_ERROR(
					!hostedController->hostedResourceManager,
					L"vl::presentation::elements::GuiHostedGraphicsResourceManager::GuiHostedGraphicsResourceManager(GuiHostedController*, IGuiGraphicsResourceManager*)#"
					L"GuiHostedGraphicsResourceManager has been created for the same GuiHostedController");
				hostedController->hostedResourceManager = this;
			}

			GuiHostedGraphicsResourceManager::~GuiHostedGraphicsResourceManager()
			{
				hostedController->hostedResourceManager = nullptr;
			}

			vint GuiHostedGraphicsResourceManager::RegisterElementType(const WString& elementTypeName)
			{
				return nativeManager->RegisterElementType(elementTypeName);
			}

			void GuiHostedGraphicsResourceManager::RegisterRendererFactory(vint elementType, Ptr<IGuiGraphicsRendererFactory> factory)
			{
				nativeManager->RegisterRendererFactory(elementType, factory);
			}

			IGuiGraphicsRendererFactory* GuiHostedGraphicsResourceManager::GetRendererFactory(vint elementType)
			{
				return nativeManager->GetRendererFactory(elementType);
			}

			IGuiGraphicsRenderTarget* GuiHostedGraphicsResourceManager::GetRenderTarget(INativeWindow* window)
			{
				return nativeManager->GetRenderTarget(hostedController->nativeWindow);
			}

			void GuiHostedGraphicsResourceManager::RecreateRenderTarget(INativeWindow* window)
			{
			}

			void GuiHostedGraphicsResourceManager::ResizeRenderTarget(INativeWindow* window)
			{
			}

			IGuiGraphicsLayoutProvider* GuiHostedGraphicsResourceManager::GetLayoutProvider()
			{
				return nativeManager->GetLayoutProvider();
			}

			Ptr<IGuiGraphicsElement> GuiHostedGraphicsResourceManager::CreateRawElement()
			{
				return nativeManager->CreateRawElement();
			}
		}
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\HOSTED\GUIHOSTEDWINDOW.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{

/***********************************************************************
GuiHostedWindow
***********************************************************************/

		void GuiHostedWindow::BecomeMainWindow()
		{
			proxy = CreateMainHostedWindowProxy(this, controller->nativeWindow);
			proxy->CheckAndSyncProperties();
			proxy->SuggestMinClientSize(suggestedMinClientSize);
		}

		void GuiHostedWindow::BecomeNonMainWindow()
		{
			proxy = CreateNonMainHostedWindowProxy(this, controller->nativeWindow);
			proxy->CheckAndSyncProperties();
			proxy->SuggestMinClientSize(suggestedMinClientSize);
		}

		void GuiHostedWindow::BecomeFocusedWindow()
		{
			CHECK_ERROR(&wmWindow == controller->wmManager->activeWindow, L"vl::presentation::GuiHostedWindow::BecomeFocusedWindow()#Wrong timing to call this function.");
			controller->nativeWindow->SetCaretPoint(windowCaretPoint + GetRenderingOffset());
		}

		void GuiHostedWindow::BecomeHoveringWindow()
		{
			CHECK_ERROR(this == controller->hoveringWindow, L"vl::presentation::GuiHostedWindow::BecomeFocusedWindow()#Wrong timing to call this function.");
			controller->nativeWindow->SetWindowCursor(windowCursor);
		}

		GuiHostedWindow::GuiHostedWindow(GuiHostedController* _controller, INativeWindow::WindowMode _windowMode)
			: GuiHostedWindowData(_controller, this, _windowMode)
		{
			wmWindow.bounds = { {0,0},{1,1} };
			proxy = CreatePlaceholderHostedWindowProxy(this);
			proxy->CheckAndSyncProperties();
		}

		GuiHostedWindow::~GuiHostedWindow()
		{
			for (auto listener : listeners)
			{
				listener->Destroyed();
			}
		}

		bool GuiHostedWindow::IsActivelyRefreshing()
		{
			return false;
		}

		NativeSize GuiHostedWindow::GetRenderingOffset()
		{
			auto pos = wmWindow.bounds.LeftTop();
			return { pos.x,pos.y };
		}

		Point GuiHostedWindow::Convert(NativePoint value)
		{
			return controller->nativeWindow->Convert(value);
		}

		NativePoint GuiHostedWindow::Convert(Point value)
		{
			return controller->nativeWindow->Convert(value);
		}

		Size GuiHostedWindow::Convert(NativeSize value)
		{
			return controller->nativeWindow->Convert(value);
		}

		NativeSize GuiHostedWindow::Convert(Size value)
		{
			return controller->nativeWindow->Convert(value);
		}

		Margin GuiHostedWindow::Convert(NativeMargin value)
		{
			return controller->nativeWindow->Convert(value);
		}

		NativeMargin GuiHostedWindow::Convert(Margin value)
		{
			return controller->nativeWindow->Convert(value);
		}

		NativeRect GuiHostedWindow::GetBounds()
		{
			return wmWindow.bounds;
		}

		void GuiHostedWindow::SetBounds(const NativeRect& bounds)
		{
			auto fixedBounds = proxy->FixBounds(bounds);
			if (wmWindow.bounds == fixedBounds) return;
			wmWindow.SetBounds(fixedBounds);
			proxy->UpdateBounds();
		}

		NativeSize GuiHostedWindow::GetClientSize()
		{
			return GetBounds().GetSize();
		}

		void GuiHostedWindow::SetClientSize(NativeSize size)
		{
			SetBounds({ GetBounds().LeftTop(),size });
		}

		NativeRect GuiHostedWindow::GetClientBoundsInScreen()
		{
			return GetBounds();
		}

		void GuiHostedWindow::SuggestMinClientSize(NativeSize size)
		{
			suggestedMinClientSize = size;
			proxy->SuggestMinClientSize(suggestedMinClientSize);
		}

		WString GuiHostedWindow::GetTitle()
		{
			return windowTitle;
		}

		void GuiHostedWindow::SetTitle(const WString& title)
		{
			if (windowTitle == title) return;
			windowTitle = title;
			proxy->UpdateTitle();
		}

		INativeCursor* GuiHostedWindow::GetWindowCursor()
		{
			return windowCursor;
		}

		void GuiHostedWindow::SetWindowCursor(INativeCursor* cursor)
		{
			if (windowCursor == cursor) return;
			windowCursor = cursor;
			if (this == controller->hoveringWindow)
			{
				controller->nativeWindow->SetWindowCursor(windowCursor);
			}
		}

		NativePoint GuiHostedWindow::GetCaretPoint()
		{
			return windowCaretPoint;
		}

		void GuiHostedWindow::SetCaretPoint(NativePoint point)
		{
			if (windowCaretPoint == point) return;
			windowCaretPoint = point;
			if (&wmWindow == controller->wmManager->activeWindow)
			{
				controller->nativeWindow->SetCaretPoint(windowCaretPoint + GetRenderingOffset());
			}
		}

		INativeWindow* GuiHostedWindow::GetParent()
		{
			return wmWindow.parent ? wmWindow.parent->id : nullptr;
		}

		void GuiHostedWindow::SetParent(INativeWindow* parent)
		{
			auto hostedWindow = dynamic_cast<GuiHostedWindow*>(parent);
			CHECK_ERROR(!parent || hostedWindow, L"vl::presentation::GuiHostedWindow::SetParent(INativeWindow*)#The window is not created by GuiHostedController.");
			auto parentWindow = hostedWindow ? &hostedWindow->wmWindow : nullptr;
			if (wmWindow.parent == parentWindow) return;
			wmWindow.SetParent(parentWindow);
		}

		INativeWindow::WindowMode GuiHostedWindow::GetWindowMode()
		{
			return windowMode;
		}

		void GuiHostedWindow::EnableCustomFrameMode()
		{
			if (windowCustomFrameMode) return;
			windowCustomFrameMode = true;
			proxy->UpdateCustomFrameMode();
		}

		void GuiHostedWindow::DisableCustomFrameMode()
		{
			if (!windowCustomFrameMode) return;
			windowCustomFrameMode = false;
			proxy->UpdateCustomFrameMode();
		}

		bool GuiHostedWindow::IsCustomFrameModeEnabled()
		{
			return windowCustomFrameMode;
		}

		NativeMargin GuiHostedWindow::GetCustomFramePadding()
		{
			return controller->nativeWindow->GetCustomFramePadding();
		}

		Ptr<GuiImageData> GuiHostedWindow::GetIcon()
		{
			if (windowIcon) return windowIcon;
			if (controller->nativeWindow)return controller->nativeWindow->GetIcon();
			return nullptr;
		}

		void GuiHostedWindow::SetIcon(Ptr<GuiImageData> icon)
		{
			if (windowIcon == icon) return;
			windowIcon = icon;
			proxy->UpdateIcon();
		}

		INativeWindow::WindowSizeState GuiHostedWindow::GetSizeState()
		{
			return windowSizeState;
		}

		void GuiHostedWindow::Show()
		{
			EnableActivate();
			proxy->Show();
		}

		void GuiHostedWindow::ShowDeactivated()
		{
			proxy->ShowDeactivated();
		}

		void GuiHostedWindow::ShowRestored()
		{
			proxy->ShowRestored();
		}

		void GuiHostedWindow::ShowMaximized()
		{
			proxy->ShowMaximized();
		}

		void GuiHostedWindow::ShowMinimized()
		{
			proxy->ShowMinimized();
		}

		void GuiHostedWindow::Hide(bool closeWindow)
		{
			if (!wmWindow.visible) return;

			if (this != controller->mainWindow)
			{
				// when the main window is being closed
				// the underlying INativeWindow will run the process
				// so we don't need to worry about it here
				bool cancel = false;
				for (auto listener : listeners)
				{
					listener->BeforeClosing(cancel);
					if (cancel) return;
				}
				for (auto listener : listeners)
				{
					listener->AfterClosing();
				}
			}

			if (closeWindow)
			{
				proxy->Close();
			}
			else
			{
				proxy->Hide();
			}
		}

		bool GuiHostedWindow::IsVisible()
		{
			return wmWindow.visible;
		}

		void GuiHostedWindow::Enable()
		{
			if (wmWindow.enabled) return;
			wmWindow.SetEnabled(true);
			proxy->UpdateEnabled();
		}

		void GuiHostedWindow::Disable()
		{
			if (!wmWindow.enabled) return;
			wmWindow.SetEnabled(false);
			proxy->UpdateEnabled();
		}

		bool GuiHostedWindow::IsEnabled()
		{
			return wmWindow.enabled;
		}

		void GuiHostedWindow::SetActivate()
		{
			EnableActivate();
			proxy->SetFocus();
		}

		bool GuiHostedWindow::IsActivated()
		{
			return wmWindow.active;
		}

		bool GuiHostedWindow::IsRenderingAsActivated()
		{
			return wmWindow.renderedAsActive;
		}

		void GuiHostedWindow::ShowInTaskBar()
		{
			if (windowShowInTaskBar) return;
			windowShowInTaskBar = true;
			proxy->UpdateShowInTaskBar();
		}

		void GuiHostedWindow::HideInTaskBar()
		{
			if (!windowShowInTaskBar) return;
			windowShowInTaskBar = false;
			proxy->UpdateShowInTaskBar();
		}

		bool GuiHostedWindow::IsAppearedInTaskBar()
		{
			return windowShowInTaskBar;
		}

		void GuiHostedWindow::EnableActivate()
		{
			if (windowEnabledActivate) return;
			windowEnabledActivate = true;
			proxy->UpdateEnabledActivate();
		}

		void GuiHostedWindow::DisableActivate()
		{
			if (!windowEnabledActivate) return;
			windowEnabledActivate = false;
			proxy->UpdateEnabledActivate();
		}

		bool GuiHostedWindow::IsEnabledActivate()
		{
			return windowEnabledActivate;
		}

		bool GuiHostedWindow::RequireCapture()
		{
			if (controller->capturingWindow) return false;
			controller->capturingWindow = this;
			controller->nativeWindow->RequireCapture();
			return true;
		}

		bool GuiHostedWindow::ReleaseCapture()
		{
			if (controller->capturingWindow != this) return false;
			controller->capturingWindow = nullptr;
			controller->nativeWindow->ReleaseCapture();
			controller->UpdateEnteringWindow(controller->hoveringWindow);
			return true;
		}

		bool GuiHostedWindow::IsCapturing()
		{
			return controller->capturingWindow == this;
		}

		bool GuiHostedWindow::GetMaximizedBox()
		{
			return windowMaximizedBox;
		}

		void GuiHostedWindow::SetMaximizedBox(bool visible)
		{
			if (windowMaximizedBox == visible) return;
			windowMaximizedBox = visible;
			proxy->UpdateMaximizedBox();
		}

		bool GuiHostedWindow::GetMinimizedBox()
		{
			return windowMinimizedBox;
		}

		void GuiHostedWindow::SetMinimizedBox(bool visible)
		{
			if (windowMinimizedBox == visible) return;
			windowMinimizedBox = visible;
			proxy->UpdateMinimizedBox();
		}

		bool GuiHostedWindow::GetBorder()
		{
			return windowBorder;
		}

		void GuiHostedWindow::SetBorder(bool visible)
		{
			if (windowBorder == visible) return;
			windowBorder = visible;
			proxy->UpdateBorderVisible();
		}

		bool GuiHostedWindow::GetSizeBox()
		{
			return windowSizeBox;
		}

		void GuiHostedWindow::SetSizeBox(bool visible)
		{
			if (windowSizeBox == visible) return;
			windowSizeBox = visible;
			proxy->UpdateSizeBox();
		}

		bool GuiHostedWindow::GetIconVisible()
		{
			return windowIconVisible;
		}

		void GuiHostedWindow::SetIconVisible(bool visible)
		{
			if (windowIconVisible == visible) return;
			windowIconVisible = visible;
			proxy->UpdateIconVisible();
		}

		bool GuiHostedWindow::GetTitleBar()
		{
			return windowTitleBar;
		}

		void GuiHostedWindow::SetTitleBar(bool visible)
		{
			if (windowTitleBar == visible) return;
			windowTitleBar = visible;
			proxy->UpdateTitleBar();
		}

		bool GuiHostedWindow::GetTopMost()
		{
			return wmWindow.topMost;
		}

		void GuiHostedWindow::SetTopMost(bool topmost)
		{
			if (wmWindow.topMost == topmost) return;
			wmWindow.SetTopMost(topmost);
			proxy->UpdateTopMost();
		}

		void GuiHostedWindow::SupressAlt()
		{
			controller->nativeWindow->SupressAlt();
		}

		bool GuiHostedWindow::InstallListener(INativeWindowListener* listener)
		{
			if (listeners.Contains(listener))
			{
				return false;
			}
			else
			{
				listeners.Add(listener);
				return true;
			}
		}

		bool GuiHostedWindow::UninstallListener(INativeWindowListener* listener)
		{
			if (listeners.Contains(listener))
			{
				listeners.Remove(listener);
				return true;
			}
			else
			{
				return false;
			}
		}

		void GuiHostedWindow::RedrawContent()
		{
		}
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\HOSTED\GUIHOSTEDWINDOWPROXY_MAIN.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{

/***********************************************************************
GuiMainHostedWindowProxy
***********************************************************************/

		class GuiMainHostedWindowProxy
			: public Object
			, public virtual IGuiHostedWindowProxy
		{
		protected:
			GuiHostedWindowData*			data = nullptr;
			INativeWindow*					nativeWindow = nullptr;

		public:

			GuiMainHostedWindowProxy(GuiHostedWindowData* _data, INativeWindow* _nativeWindow)
				: data(_data)
				, nativeWindow(_nativeWindow)
			{
			}

			void CheckAndSyncProperties() override
			{
				for (auto listener : data->listeners)
				{
					listener->AssignFrameConfig(data->controller->WindowService()->GetMainWindowFrameConfig());
				}

				if (!data->wmWindow.visible)
				{
					data->wmWindow.Show();
				}
				data->wmWindow.SetBounds(FixBounds(data->wmWindow.bounds));

				UpdateBounds();
				UpdateTitle();
				UpdateIcon();
				UpdateEnabled();
				UpdateTopMost();

				UpdateMaximizedBox();
				UpdateMinimizedBox();
				UpdateBorderVisible();
				UpdateSizeBox();
				UpdateIconVisible();
				UpdateTitleBar();

				UpdateShowInTaskBar();
				UpdateEnabledActivate();
				UpdateCustomFrameMode();
			}

			/***********************************************************************
			Visible Properties
			***********************************************************************/

			NativeRect FixBounds(const NativeRect& bounds) override
			{
				return { {},bounds.GetSize() };
			}

			void SuggestMinClientSize(NativeSize size) override
			{
				nativeWindow->SuggestMinClientSize(size);
			}

			void UpdateBounds() override
			{
				nativeWindow->SetClientSize(data->wmWindow.bounds.GetSize());
			}

			void UpdateTitle() override
			{
				nativeWindow->SetTitle(data->windowTitle);
			}

			void UpdateIcon() override
			{
				nativeWindow->SetIcon(data->windowIcon);
			}

			void UpdateEnabled() override
			{
				// Disabling the main window will not disable the native window
				// otherwise the whole application is disabled
			}

			void UpdateTopMost() override
			{
				nativeWindow->SetTopMost(data->wmWindow.topMost);
			}

			/***********************************************************************
			Border Properties
			***********************************************************************/

			void UpdateMaximizedBox() override
			{
				nativeWindow->SetMaximizedBox(data->windowMaximizedBox);
			}

			void UpdateMinimizedBox() override
			{
				nativeWindow->SetMinimizedBox(data->windowMinimizedBox);
			}

			void UpdateBorderVisible() override
			{
				nativeWindow->SetBorder(data->windowBorder);
			}

			void UpdateSizeBox() override
			{
				nativeWindow->SetSizeBox(data->windowSizeBox);
			}

			void UpdateIconVisible() override
			{
				nativeWindow->SetIconVisible(data->windowIconVisible);
			}

			void UpdateTitleBar() override
			{
				nativeWindow->SetTitleBar(data->windowTitleBar);
			}

			/***********************************************************************
			Behavior Properties
			***********************************************************************/

			void UpdateShowInTaskBar() override
			{
				if (data->windowShowInTaskBar)
				{
					nativeWindow->ShowInTaskBar();
				}
				else
				{
					nativeWindow->HideInTaskBar();
				}
			}

			void UpdateEnabledActivate() override
			{
				// In hosted mode, the native window is always activatable
			}

			void UpdateCustomFrameMode() override
			{
				if (data->windowCustomFrameMode)
				{
					nativeWindow->EnableCustomFrameMode();
				}
				else
				{
					nativeWindow->DisableCustomFrameMode();
				}
			}

			/***********************************************************************
			Show/Hide/Focus

			In hosted mode, the main window is never closed.
			Closing the main window causes the native window to be closed.
			***********************************************************************/

			void Show() override
			{
				data->wmWindow.Activate();
				nativeWindow->Show();
			}

			void ShowDeactivated() override
			{
				data->wmWindow.Deactivate();
				nativeWindow->ShowDeactivated();
			}

			void ShowRestored() override
			{
				nativeWindow->ShowRestored();
			}

			void ShowMaximized() override
			{
				nativeWindow->ShowMaximized();
			}

			void ShowMinimized() override
			{
				nativeWindow->ShowMinimized();
			}

			void Hide() override
			{
				nativeWindow->Hide(false);
			}

			void Close() override
			{
				nativeWindow->Hide(true);
			}

			void SetFocus() override
			{
				data->wmWindow.Activate();
				nativeWindow->SetActivate();
			}
		};

/***********************************************************************
Helper
***********************************************************************/

		Ptr<IGuiHostedWindowProxy> CreateMainHostedWindowProxy(GuiHostedWindowData* data, INativeWindow* nativeWindow)
		{
			return Ptr(new GuiMainHostedWindowProxy(data, nativeWindow));
		}
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\HOSTED\GUIHOSTEDWINDOWPROXY_NONMAIN.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{

/***********************************************************************
GuiNonMainHostedWindowProxy
***********************************************************************/

		class GuiNonMainHostedWindowProxy
			: public Object
			, public virtual IGuiHostedWindowProxy
		{
		protected:
			GuiHostedWindowData*			data = nullptr;
			INativeWindow*					nativeWindow = nullptr;
			bool							calledAssignFrameConfig = false;

		public:

			GuiNonMainHostedWindowProxy(GuiHostedWindowData* _data, INativeWindow* _nativeWindow)
				: data(_data)
				, nativeWindow(_nativeWindow)
			{
			}

			void EnsureNoSystemBorderWhenVisible()
			{
				if (!data->wmWindow.visible) return;
				if (data->windowCustomFrameMode) return;
				CHECK_ERROR(
					!data->windowBorder && !data->windowSizeBox && !data->windowTitleBar,
					L"vl::presentation::GuiNonMainHostedWindowProxy::EnsureNoSystemBorder()#"
					L"For non main window in hosted mode, when custom frame mode is disabled"
					L"the following window features should also be disabled: "
					L"Border, SizeBox, TitleBar.");
			}

			void CallAssignFrameConfigIfNever()
			{
				if (calledAssignFrameConfig) return;
				for (auto listener : data->listeners)
				{
					listener->AssignFrameConfig(data->controller->WindowService()->GetNonMainWindowFrameConfig());
					calledAssignFrameConfig = true;
				}
			}

			void CheckAndSyncProperties() override
			{
				data->windowMaximizedBox = false;
				data->windowMinimizedBox = false;
				CallAssignFrameConfigIfNever();
				EnsureNoSystemBorderWhenVisible();
			}

			/***********************************************************************
			Visible Properties
			***********************************************************************/

			NativeRect FixBounds(const NativeRect& bounds) override
			{
				auto w = bounds.Width().value;
				auto h = bounds.Height().value;
				if (w < 1) w = 1;
				if (h < 1) h = 1;
				return { bounds.LeftTop(),{{w},{h}} };
			}

			void SuggestMinClientSize(NativeSize size) override
			{
				// Ignored
			}

			void UpdateBounds() override
			{
			}

			void UpdateTitle() override
			{
			}

			void UpdateIcon() override
			{
			}

			void UpdateEnabled() override
			{
			}

			void UpdateTopMost() override
			{
			}

			/***********************************************************************
			Border Properties
			***********************************************************************/

			void UpdateMaximizedBox() override
			{
				if (data->windowMaximizedBox)
				{
					data->windowMaximizedBox = false;
				}
			}

			void UpdateMinimizedBox() override
			{
				if (data->windowMinimizedBox)
				{
					data->windowMinimizedBox = false;
				}
			}

			void UpdateBorderVisible() override
			{
				EnsureNoSystemBorderWhenVisible();
			}

			void UpdateSizeBox() override
			{
				EnsureNoSystemBorderWhenVisible();
			}

			void UpdateIconVisible() override
			{
			}

			void UpdateTitleBar() override
			{
				EnsureNoSystemBorderWhenVisible();
			}

			/***********************************************************************
			Behavior Properties
			***********************************************************************/

			void UpdateShowInTaskBar() override
			{
			}

			void UpdateEnabledActivate() override
			{
			}

			void UpdateCustomFrameMode() override
			{
				EnsureNoSystemBorderWhenVisible();
			}

			/***********************************************************************
			Show/Hide/Focus

			Maximized and Minimized are not available
			***********************************************************************/

			void Show() override
			{
				CallAssignFrameConfigIfNever();
				data->wmWindow.SetVisible(true);
				data->wmWindow.Activate();
				EnsureNoSystemBorderWhenVisible();
			}

			void ShowDeactivated() override
			{
				CallAssignFrameConfigIfNever();
				data->wmWindow.SetVisible(true);
				EnsureNoSystemBorderWhenVisible();
			}

			void ShowRestored() override
			{
				Show();
			}

			void ShowMaximized() override
			{
				Show();
			}

			void ShowMinimized() override
			{
				Show();
			}

			void Hide() override
			{
				data->wmWindow.SetVisible(false);
			}

			void Close() override
			{
				Hide();
			}

			void SetFocus() override
			{
				if (data->wmWindow.visible)
				{
					data->wmWindow.Activate();
					nativeWindow->SetActivate();
				}
			}
		};

/***********************************************************************
Helper
***********************************************************************/

		Ptr<IGuiHostedWindowProxy> CreateNonMainHostedWindowProxy(GuiHostedWindowData* data, INativeWindow* nativeWindow)
		{
			return Ptr(new GuiNonMainHostedWindowProxy(data, nativeWindow));
		}
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\HOSTED\GUIHOSTEDWINDOWPROXY_PLACEHOLDER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{

/***********************************************************************
GuiPlaceholderHostedWindowProxy
***********************************************************************/

		class GuiPlaceholderHostedWindowProxy
			: public Object
			, public virtual IGuiHostedWindowProxy
		{
		protected:
			GuiHostedWindowData*			data = nullptr;

		public:

			GuiPlaceholderHostedWindowProxy(GuiHostedWindowData* _data)
				: data(_data)
			{
			}

			void CheckAndSyncProperties() override
			{
			}

			/***********************************************************************
			Visible Properties
			***********************************************************************/

			NativeRect FixBounds(const NativeRect& bounds) override
			{
				return bounds;
			}

			void SuggestMinClientSize(NativeSize size) override
			{
				// Ignored
			}

			void UpdateBounds() override
			{
			}

			void UpdateTitle() override
			{
			}

			void UpdateIcon() override
			{
			}

			void UpdateEnabled() override
			{
			}

			void UpdateTopMost() override
			{
			}

			/***********************************************************************
			Border Properties
			***********************************************************************/

			void UpdateMaximizedBox() override
			{
			}

			void UpdateMinimizedBox() override
			{
			}

			void UpdateBorderVisible() override
			{
			}

			void UpdateSizeBox() override
			{
			}

			void UpdateIconVisible() override
			{
			}

			void UpdateTitleBar() override
			{
			}

			/***********************************************************************
			Behavior Properties
			***********************************************************************/

			void UpdateShowInTaskBar() override
			{
			}

			void UpdateEnabledActivate() override
			{
			}

			void UpdateCustomFrameMode() override
			{
			}

			/***********************************************************************
			Show/Hide/Focus
			***********************************************************************/

			void Show() override
			{
				CHECK_FAIL(L"vl::presentation::GuiPlaceholderHostedWindowProxy::Show()#This function should not be called.");
			}

			void ShowDeactivated() override
			{
				CHECK_FAIL(L"vl::presentation::GuiPlaceholderHostedWindowProxy::ShowDeactivated()#This function should not be called.");
			}

			void ShowRestored() override
			{
				CHECK_FAIL(L"vl::presentation::GuiPlaceholderHostedWindowProxy::ShowRestored()#This function should not be called.");
			}

			void ShowMaximized() override
			{
				CHECK_FAIL(L"vl::presentation::GuiPlaceholderHostedWindowProxy::ShowMaximized()#This function should not be called.");
			}

			void ShowMinimized() override
			{
				CHECK_FAIL(L"vl::presentation::GuiPlaceholderHostedWindowProxy::ShowMinimized()#This function should not be called.");
			}

			void Hide() override
			{
			}

			void Close() override
			{
			}

			void SetFocus() override
			{
			}
		};

/***********************************************************************
Helper
***********************************************************************/

		Ptr<IGuiHostedWindowProxy> CreatePlaceholderHostedWindowProxy(GuiHostedWindowData* data)
		{
			return Ptr(new GuiPlaceholderHostedWindowProxy(data));
		}
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTECONTROLLER.CPP
***********************************************************************/

namespace vl::presentation
{
	using namespace collections;

/***********************************************************************
GuiRemoteCursor
***********************************************************************/

	class GuiRemoteCursor : public Object, public virtual INativeCursor
	{
	protected:
		INativeCursor::SystemCursorType								cursorType;

	public:
		GuiRemoteCursor(INativeCursor::SystemCursorType _cursorType) : cursorType(_cursorType) {}

		bool				IsSystemCursor() { return true; }
		SystemCursorType	GetSystemCursorType() { return cursorType; }
	};
		
/***********************************************************************
GuiRemoteController::INativeResourceService
***********************************************************************/

	INativeCursor* GuiRemoteController::GetSystemCursor(INativeCursor::SystemCursorType type)
	{
		vint index = cursors.Keys().IndexOf(type);
		if (index == -1)
		{
			auto cursor = Ptr(new GuiRemoteCursor(type));
			cursors.Add(type, cursor);
			return cursor.Obj();
		}
		else
		{
			return cursors.Values()[index].Obj();
		}
	}

	INativeCursor* GuiRemoteController::GetDefaultSystemCursor()
	{
		return GetSystemCursor(INativeCursor::SystemCursorType::Arrow);
	}

	FontProperties GuiRemoteController::GetDefaultFont()
	{
		return remoteFontConfig.defaultFont;
	}

	void GuiRemoteController::SetDefaultFont(const FontProperties& value)
	{
		remoteFontConfig.defaultFont = value;
	}

	void GuiRemoteController::EnumerateFonts(collections::List<WString>& fonts)
	{
		if (remoteFontConfig.supportedFonts)
		{
			CopyFrom(fonts, *remoteFontConfig.supportedFonts.Obj());
		}
	}
			
/***********************************************************************
GuiRemoteController::INativeInputService
***********************************************************************/

	void GuiRemoteController::StartTimer()
	{
		timerEnabled = true;
	}

	void GuiRemoteController::StopTimer()
	{
		timerEnabled = false;
	}

	bool GuiRemoteController::IsTimerEnabled()
	{
		return timerEnabled;
	}

	bool GuiRemoteController::IsKeyPressing(VKEY code)
	{
		vint idIsKeyPressing = remoteMessages.RequestIOIsKeyPressing(code);
		bool disconnected = false;
		remoteMessages.Submit(disconnected);
		if (disconnected) return false;
		bool result = remoteMessages.RetrieveIOIsKeyPressing(idIsKeyPressing);
		return result;
	}

	bool GuiRemoteController::IsKeyToggled(VKEY code)
	{
		vint idIsKeyToggled = remoteMessages.RequestIOIsKeyToggled(code);
		bool disconnected = false;
		remoteMessages.Submit(disconnected);
		if (disconnected) return false;
		bool result = remoteMessages.RetrieveIOIsKeyToggled(idIsKeyToggled);
		return result;
	}

	void GuiRemoteController::EnsureKeyInitialized()
	{
		if (keyInitialized) return;
		keyInitialized = true;

#define INITIALIZE_KEY_NAME(NAME, TEXT)\
		keyNames.Add(VKEY::KEY_ ## NAME, WString::Unmanaged(TEXT));\
		if (!keyCodes.Keys().Contains(WString::Unmanaged(TEXT))) keyCodes.Add(WString::Unmanaged(TEXT), VKEY::KEY_ ## NAME);\

		GUI_DEFINE_KEYBOARD_WINDOWS_NAME(INITIALIZE_KEY_NAME)
#undef INITIALIZE_KEY_NAME
	}

	WString GuiRemoteController::GetKeyName(VKEY code)
	{
		EnsureKeyInitialized();
		vint index = keyNames.Keys().IndexOf(code);
		return index == -1 ? WString::Unmanaged(L"?") : keyNames.Values()[index];
	}

	VKEY GuiRemoteController::GetKey(const WString& name)
	{
		EnsureKeyInitialized();
		vint index = keyCodes.Keys().IndexOf(name);
		return index == -1 ? VKEY::KEY_UNKNOWN : keyCodes.Values()[index];
	}

	void GuiRemoteController::UpdateGlobalShortcutKey()
	{
		auto hotKeys = Ptr(new List<remoteprotocol::GlobalShortcutKey>);
		for (auto [id, entry] : hotKeyIds)
		{
			remoteprotocol::GlobalShortcutKey key;
			key.id = id;
			key.ctrl = entry.get<0>();
			key.shift = entry.get<1>();
			key.alt = entry.get<2>();
			key.code = entry.get<3>();
			hotKeys->Add(key);
		}
		remoteMessages.RequestIOUpdateGlobalShortcutKey(hotKeys);
	}

	vint GuiRemoteController::RegisterGlobalShortcutKey(bool ctrl, bool shift, bool alt, VKEY key)
	{
		HotKeyEntry entry = { ctrl,shift,alt,key };
		if (hotKeySet.Contains(entry)) return (vint)NativeGlobalShortcutKeyResult::Occupied;

		vint id = ++usedHotKeys;
		hotKeySet.Add(entry);
		hotKeyIds.Add(id, entry);

		UpdateGlobalShortcutKey();
		bool disconnected = false;
		remoteMessages.Submit(disconnected);
		// there is no result from this request, assuming succeeded

		return id;
	}
		
	bool GuiRemoteController::UnregisterGlobalShortcutKey(vint id)
	{
		vint index = hotKeyIds.Keys().IndexOf(id);
		if (index == -1) return false;

		auto entry = hotKeyIds.Values()[index];
		hotKeyIds.Remove(id);
		hotKeySet.Remove(entry);

		UpdateGlobalShortcutKey();
		bool disconnected = false;
		remoteMessages.Submit(disconnected);
		// there is no result from this request, assuming succeeded

		return true;
	}

	void GuiRemoteController::EnsureControllerConnected()
	{
		if (!controllerConnected && !connectionStopped)
		{
			bool disconnected = false;
			remoteMessages.Submit(disconnected);
			RunOneCycle();
		}
	}

/***********************************************************************
GuiRemoteController::INativeScreenService
***********************************************************************/

	vint GuiRemoteController::GetScreenCount()
	{
		return 1;
	}

	INativeScreen* GuiRemoteController::GetScreen(vint index)
	{
		CHECK_ERROR(index == 0, L"vl::presentation::GuiRemoteController::GetScreen(vint)#Index out of range.");
		return this;
	}

	INativeScreen* GuiRemoteController::GetScreen(INativeWindow* window)
	{
		return this;
	}

/***********************************************************************
GuiHostedController::INativeScreen
***********************************************************************/

	NativeRect GuiRemoteController::GetBounds()
	{
		EnsureControllerConnected();
		return remoteScreenConfig.bounds;
	}

	NativeRect GuiRemoteController::GetClientBounds()
	{
		EnsureControllerConnected();
		return remoteScreenConfig.clientBounds;
	}

	WString GuiRemoteController::GetName()
	{
		return WString::Unmanaged(L"GacUI Virtual Remote Screen");
	}

	bool GuiRemoteController::IsPrimary()
	{
		return true;
	}

	double GuiRemoteController::GetScalingX()
	{
		EnsureControllerConnected();
		return remoteScreenConfig.scalingX;
	}

	double GuiRemoteController::GetScalingY()
	{
		EnsureControllerConnected();
		return remoteScreenConfig.scalingY;
	}

/***********************************************************************
GuiRemoteController::INativeWindowService
***********************************************************************/

	const NativeWindowFrameConfig& GuiRemoteController::GetMainWindowFrameConfig()
	{
		return NativeWindowFrameConfig::Default;
	}

	const NativeWindowFrameConfig& GuiRemoteController::GetNonMainWindowFrameConfig()
	{
		return NativeWindowFrameConfig::Default;
	}

	INativeWindow* GuiRemoteController::CreateNativeWindow(INativeWindow::WindowMode windowMode)
	{
		CHECK_ERROR(!windowCreated, L"vl::presentation::GuiRemoteController::CreateNativeWindow(INativeWindow::WindowMode)#GuiHostedController is not supposed to call this function for twice.");
		windowCreated = true;
		remoteWindow.windowMode = windowMode;
		callbackService.InvokeNativeWindowCreated(&remoteWindow);
		return &remoteWindow;
	}

	void GuiRemoteController::DestroyNativeWindow(INativeWindow* window)
	{
		CHECK_ERROR(!windowDestroyed, L"vl::presentation::GuiRemoteController::CreateNativeWindow(INativeWindow::WindowMode)#GuiHostedController is not supposed to call this function for twice.");
		windowDestroyed = true;

		for (auto l : remoteWindow.listeners) l->Closed();
		for (auto l : remoteWindow.listeners) l->Destroying();
		callbackService.InvokeNativeWindowDestroying(&remoteWindow);
		for (auto l : remoteWindow.listeners) l->Destroyed();
		connectionStopped = true;
	}

	INativeWindow* GuiRemoteController::GetMainWindow()
	{
		return windowCreated  && !windowDestroyed ? &remoteWindow : nullptr;
	}

	INativeWindow* GuiRemoteController::GetWindow(NativePoint location)
	{
		return GetMainWindow();
	}

	void GuiRemoteController::Run(INativeWindow* window)
	{
		CHECK_ERROR(window == &remoteWindow, L"vl::presentation::GuiRemoteController::Run(INativeWindow*)#GuiHostedController should call this function with the native window.");
		applicationRunning = true;
		if (controllerConnected)
		{
			remoteWindow.SubmitStateAfterControllerConnect();
		}
		window->Show();
		while (RunOneCycle());
		asyncService.ExecuteAsyncTasks();
		applicationRunning = false;
	}

	bool GuiRemoteController::RunOneCycle()
	{
		if (!connectionStopped)
		{
			if (auto processor = remoteProtocol->GetRemoteEventProcessor())
			{
				processor->ProcessRemoteEvents();
			}
			bool disconnected = false;
			remoteMessages.Submit(disconnected);
			if (timerEnabled && !disconnected)
			{
				callbackService.InvokeGlobalTimer();
			}
			asyncService.ExecuteAsyncTasks();
		}
		return !connectionStopped;
	}

/***********************************************************************
GuiRemoteController (events)
***********************************************************************/

	void GuiRemoteController::OnControllerConnect(const remoteprotocol::ControllerGlobalConfig& _globalConfig)
	{
		controllerConnected = true;
		remoteGlobalConfig = _globalConfig;
		UpdateGlobalShortcutKey();
		vint idGetFontConfig = remoteMessages.RequestControllerGetFontConfig();
		vint idGetScreenConfig = remoteMessages.RequestControllerGetScreenConfig();
		bool disconnected = false;
		remoteMessages.Submit(disconnected);
		if (disconnected) return;
		remoteFontConfig = remoteMessages.RetrieveControllerGetFontConfig(idGetFontConfig);
		remoteScreenConfig = remoteMessages.RetrieveControllerGetScreenConfig(idGetScreenConfig);
		remoteWindow.OnControllerConnect();
		imageService.OnControllerConnect();
		resourceManager->OnControllerConnect();
		callbackService.InvokeEnvironmentChanged();
	}

	void GuiRemoteController::OnControllerDisconnect()
	{
		controllerConnected = false;
		remoteWindow.OnControllerDisconnect();
		imageService.OnControllerDisconnect();
		resourceManager->OnControllerDisconnect();
	}

	void GuiRemoteController::OnControllerRequestExit()
	{
		remoteWindow.Hide(true);
	}

	void GuiRemoteController::OnControllerForceExit()
	{
		connectionForcedToStop = true;
		remoteWindow.Hide(true);
	}

	void GuiRemoteController::OnControllerScreenUpdated(const remoteprotocol::ScreenConfig& arguments)
	{
		remoteScreenConfig = arguments;
		remoteWindow.OnControllerScreenUpdated(arguments);
	}

/***********************************************************************
GuiRemoteController
***********************************************************************/

	GuiRemoteController::GuiRemoteController(IGuiRemoteProtocol* _remoteProtocol)
		: remoteProtocol(_remoteProtocol)
		, remoteMessages(this)
		, remoteEvents(this)
		, remoteWindow(this)
		, imageService(this)
	{
#if defined VCZH_WCHAR_UTF16
		remoteGlobalConfig.documentCaretFromEncoding = remoteprotocol::CharacterEncoding::UTF16;
#elif defined VCZH_WCHAR_UTF32
		remoteGlobalConfig.documentCaretFromEncoding = remoteprotocol::CharacterEncoding::UTF32;
#endif
		remoteFontConfig.defaultFont.size = 12;
	}

	GuiRemoteController::~GuiRemoteController()
	{
	}

	void GuiRemoteController::Initialize()
	{
		remoteProtocol->Initialize(&remoteEvents);
		imageService.Initialize();
	}

	void GuiRemoteController::Finalize()
	{
		imageService.Finalize();
		remoteMessages.RequestControllerConnectionStopped();
		bool disconnected = false;
		remoteMessages.Submit(disconnected);
		// there is no result from this request, assuming succeeded
	}

	remoteprotocol::ControllerGlobalConfig GuiRemoteController::GetGlobalConfig()
	{
		return remoteGlobalConfig;
	}

/***********************************************************************
GuiRemoteController (INativeController)
***********************************************************************/

	INativeCallbackService* GuiRemoteController::CallbackService()
	{
		return &callbackService;
	}

	INativeResourceService* GuiRemoteController::ResourceService()
	{
		return this;
	}

	INativeAsyncService* GuiRemoteController::AsyncService()
	{
		return &asyncService;
	}

	INativeClipboardService* GuiRemoteController::ClipboardService()
	{
		// Use FakeClipboardService
		return nullptr;
	}

	INativeImageService* GuiRemoteController::ImageService()
	{
		return &imageService;
	}

	INativeInputService* GuiRemoteController::InputService()
	{
		return this;
	}

	INativeDialogService* GuiRemoteController::DialogService()
	{
		// Use FakeDialogServiceBase
		return nullptr;
	}

	INativeAutomationService* GuiRemoteController::AutomationService()
	{
		// Use INativeAutomationService::UnavailableService
		return nullptr;
	}

	WString GuiRemoteController::GetExecutablePath()
	{
		return remoteProtocol->GetExecutablePath();
	}
		
	INativeScreenService* GuiRemoteController::ScreenService()
	{
		return this;
	}

	INativeWindowService* GuiRemoteController::WindowService()
	{
		return this;
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTECONTROLLERSETUP.CPP
***********************************************************************/

using namespace vl;
using namespace vl::presentation;
using namespace vl::presentation::elements;

/***********************************************************************
SetupRemoteNativeController
***********************************************************************/

extern void GuiApplicationMain();

int SetupRemoteNativeController(vl::presentation::IGuiRemoteProtocol* protocol)
{
	GuiRemoteController remoteController(protocol);
	GuiHostedController hostedController(&remoteController);

	GuiRemoteGraphicsResourceManager remoteResourceManager(&remoteController, &hostedController);
	GuiHostedGraphicsResourceManager hostedResourceManager(&hostedController, &remoteResourceManager);

	SetNativeController(&hostedController);
	SetGuiGraphicsResourceManager(&hostedResourceManager);
	SetHostedApplication(hostedController.GetHostedApplication());

	remoteController.Initialize();
	remoteResourceManager.Initialize();
	hostedController.Initialize();
	GuiApplicationMain();
	hostedController.Finalize();
	remoteResourceManager.Finalize();
	remoteController.Finalize();

	SetHostedApplication(nullptr);
	SetGuiGraphicsResourceManager(nullptr);
	SetNativeController(nullptr);
	return 0;
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEEVENTS.CPP
***********************************************************************/

namespace vl::presentation
{

/***********************************************************************
GuiRemoteMessages
***********************************************************************/

	GuiRemoteMessages::GuiRemoteMessages(GuiRemoteController* _remote)
		: remote(_remote)
	{
	}

	GuiRemoteMessages::~GuiRemoteMessages()
	{
	}

	void GuiRemoteMessages::Submit(bool& disconnected)
	{
		remote->remoteProtocol->Submit(disconnected);
	}

/***********************************************************************
GuiRemoteMessages (messages)
***********************************************************************/

#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE)\
	void GuiRemoteMessages::Request ## NAME()\
	{\
		remote->remoteProtocol->Request ## NAME();\
	}\

#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE)\
	vint GuiRemoteMessages::Request ## NAME()\
	{\
		vint requestId = ++id;\
		remote->remoteProtocol->Request ## NAME(requestId);\
		return requestId;\
	}\

#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE)\
	void GuiRemoteMessages::Request ## NAME(const REQUEST& arguments)\
	{\
		remote->remoteProtocol->Request ## NAME(arguments);\
	}\

#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE)\
	vint GuiRemoteMessages::Request ## NAME(const REQUEST& arguments)\
	{\
		vint requestId = ++id;\
		remote->remoteProtocol->Request ## NAME(requestId, arguments);\
		return requestId;\
	}\

#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE)
	GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_REQ_RES
#undef MESSAGE_REQ_NORES
#undef MESSAGE_NOREQ_RES
#undef MESSAGE_NOREQ_NORES

#define MESSAGE_NORES(NAME, RESPONSE)
#define MESSAGE_RES(NAME, RESPONSE)\
	void GuiRemoteMessages::Respond ## NAME(vint id, const RESPONSE& arguments)\
	{\
		response ## NAME.Add(id, arguments);\
	}\
	RESPONSE GuiRemoteMessages::Retrieve ## NAME(vint id)\
	{\
		RESPONSE response = response ## NAME[id];\
		response ## NAME.Remove(id);\
		return response;\
	}\

#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## RESTAG(NAME, RESPONSE)
		GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_RES
#undef MESSAGE_NORES

/***********************************************************************
GuiRemoteEvents
***********************************************************************/

	GuiRemoteEvents::GuiRemoteEvents(GuiRemoteController* _remote)
		: remote(_remote)
	{
	}

	GuiRemoteEvents::~GuiRemoteEvents()
	{
	}

/***********************************************************************
GuiRemoteEvents (messages)
***********************************************************************/

#define MESSAGE_NORES(NAME, RESPONSE)
#define MESSAGE_RES(NAME, RESPONSE)\
	void GuiRemoteEvents::Respond ## NAME(vint id, const RESPONSE& arguments)\
	{\
		remote->remoteMessages.Respond ## NAME(id, arguments);\
	}\

#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## RESTAG(NAME, RESPONSE)
	GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_RES
#undef MESSAGE_NORES

/***********************************************************************
GuiRemoteEvents (events)
***********************************************************************/

	void GuiRemoteEvents::OnControllerConnect(const remoteprotocol::ControllerGlobalConfig& arguments)
	{
		remote->remoteMessages.RequestControllerConnectionEstablished();
		remote->OnControllerConnect(arguments);
		bool disconnected = false;
		remote->remoteMessages.Submit(disconnected);
		// there is no result from this request, assuming succeeded
		// if disconnected, OnControllerDisconnect will be called
	}

	void GuiRemoteEvents::OnControllerDisconnect()
	{
		remote->OnControllerDisconnect();
	}

	void GuiRemoteEvents::OnControllerRequestExit()
	{
		remote->OnControllerRequestExit();
	}

	void GuiRemoteEvents::OnControllerForceExit()
	{
		remote->OnControllerForceExit();
	}

	void GuiRemoteEvents::OnControllerScreenUpdated(const remoteprotocol::ScreenConfig& arguments)
	{
		remote->OnControllerScreenUpdated(arguments);
	}

	void GuiRemoteEvents::OnWindowBoundsUpdated(const remoteprotocol::WindowSizingConfig& arguments)
	{
		remote->remoteWindow.OnWindowBoundsUpdated(arguments);
	}

	void GuiRemoteEvents::OnWindowActivatedUpdated(const bool& arguments)
	{
		remote->remoteWindow.OnWindowActivatedUpdated(arguments);
	}

	void GuiRemoteEvents::OnIOGlobalShortcutKey(const vint& arguments)
	{
		remote->callbackService.InvokeGlobalShortcutKeyActivated(arguments);
	}

	void GuiRemoteEvents::OnIOButtonDown(const remoteprotocol::IOMouseInfoWithButton& arguments)
	{
		switch (arguments.button)
		{
		case remoteprotocol::IOMouseButton::Left:
			for (auto l : remote->remoteWindow.listeners) l->LeftButtonDown(arguments.info);
			break;
		case remoteprotocol::IOMouseButton::Middle:
			for (auto l : remote->remoteWindow.listeners) l->MiddleButtonDown(arguments.info);
			break;
		case remoteprotocol::IOMouseButton::Right:
			for (auto l : remote->remoteWindow.listeners) l->RightButtonDown(arguments.info);
			break;
		default:
			CHECK_FAIL(L"vl::presentation::GuiRemoteEvents::OnIOButtonDown(const IOMouseInfoWithButton&)#Unrecognized button.");
		}
	}

	void GuiRemoteEvents::OnIOButtonDoubleClick(const remoteprotocol::IOMouseInfoWithButton& arguments)
	{
		switch (arguments.button)
		{
		case remoteprotocol::IOMouseButton::Left:
			for (auto l : remote->remoteWindow.listeners) l->LeftButtonDoubleClick(arguments.info);
			break;
		case remoteprotocol::IOMouseButton::Middle:
			for (auto l : remote->remoteWindow.listeners) l->MiddleButtonDoubleClick(arguments.info);
			break;
		case remoteprotocol::IOMouseButton::Right:
			for (auto l : remote->remoteWindow.listeners) l->RightButtonDoubleClick(arguments.info);
			break;
		default:
			CHECK_FAIL(L"vl::presentation::GuiRemoteEvents::OnIOButtonDoubleClick(const IOMouseInfoWithButton&)#Unrecognized button.");
		}
	}

	void GuiRemoteEvents::OnIOButtonUp(const remoteprotocol::IOMouseInfoWithButton& arguments)
	{
		switch (arguments.button)
		{
		case remoteprotocol::IOMouseButton::Left:
			for (auto l : remote->remoteWindow.listeners) l->LeftButtonUp(arguments.info);
			break;
		case remoteprotocol::IOMouseButton::Middle:
			for (auto l : remote->remoteWindow.listeners) l->MiddleButtonUp(arguments.info);
			break;
		case remoteprotocol::IOMouseButton::Right:
			for (auto l : remote->remoteWindow.listeners) l->RightButtonUp(arguments.info);
			break;
		default:
			CHECK_FAIL(L"vl::presentation::GuiRemoteEvents::OnIOButtonUp(const IOMouseInfoWithButton&)#Unrecognized button.");
		}
	}

	void GuiRemoteEvents::OnIOHWheel(const NativeWindowMouseInfo& arguments)
	{
		for (auto l : remote->remoteWindow.listeners) l->HorizontalWheel(arguments);
	}

	void GuiRemoteEvents::OnIOVWheel(const NativeWindowMouseInfo& arguments)
	{
		for (auto l : remote->remoteWindow.listeners) l->VerticalWheel(arguments);
	}

	void GuiRemoteEvents::OnIOMouseMoving(const NativeWindowMouseInfo& arguments)
	{
		for (auto l : remote->remoteWindow.listeners) l->MouseMoving(arguments);
	}

	void GuiRemoteEvents::OnIOMouseEntered()
	{
		for (auto l : remote->remoteWindow.listeners) l->MouseEntered();
	}

	void GuiRemoteEvents::OnIOMouseLeaved()
	{
		for (auto l : remote->remoteWindow.listeners) l->MouseLeaved();
	}

	void GuiRemoteEvents::OnIOKeyDown(const NativeWindowKeyInfo& arguments)
	{
		for (auto l : remote->remoteWindow.listeners) l->KeyDown(arguments);
	}

	void GuiRemoteEvents::OnIOKeyUp(const NativeWindowKeyInfo& arguments)
	{
		for (auto l : remote->remoteWindow.listeners) l->KeyUp(arguments);
	}

	void GuiRemoteEvents::OnIOChar(const NativeWindowCharInfo& arguments)
	{
		for (auto l : remote->remoteWindow.listeners) l->Char(arguments);
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEGRAPHICS.CPP
***********************************************************************/

namespace vl::presentation::elements
{
	using namespace collections;
	using namespace compositions;

/***********************************************************************
GuiRemoteGraphicsRenderTarget
***********************************************************************/

	GuiRemoteGraphicsRenderTarget::HitTestResult GuiRemoteGraphicsRenderTarget::GetHitTestResultFromGenerator(reflection::DescriptableObject* generator)
	{
		if (auto composition = dynamic_cast<GuiGraphicsComposition*>(generator))
		{
			auto hitTestResult = composition->GetAssociatedHitTestResult();
			if (hitTestResult != INativeWindowListener::NoDecision)
			{
				if (auto graphicsHost = composition->GetRelatedGraphicsHost())
				{
					if (auto nativeWindow = graphicsHost->GetNativeWindow())
					{
						if (nativeWindow == GetCurrentController()->WindowService()->GetMainWindow())
						{
							return hitTestResult;
						}
					}
				}
			}
		}
		return INativeWindowListener::NoDecision;
	}

	Nullable<GuiRemoteGraphicsRenderTarget::SystemCursorType> GuiRemoteGraphicsRenderTarget::GetCursorFromGenerator(reflection::DescriptableObject* generator)
	{
		if (auto composition = dynamic_cast<GuiGraphicsComposition*>(generator))
		{
			if (auto graphicsHost = composition->GetRelatedGraphicsHost())
			{
				if (auto nativeWindow = graphicsHost->GetNativeWindow())
				{
					auto mainWindow = GetCurrentController()->WindowService()->GetMainWindow();
					if (auto cursor = composition->GetAssociatedCursor())
					{
						return cursor->GetSystemCursorType();
					}
					if (nativeWindow != mainWindow)
					{
						// For non-main windows, hit test is not sent via remote protocol
						// to avoid interfering with the main window's border behavior.
						// Translate hit test to cursor here since native OS provider
						// won't be able to do it without hit test information.
						auto hitTestResult = composition->GetAssociatedHitTestResult();
						if (hitTestResult != INativeWindowListener::NoDecision)
						{
							auto cursor = GetCursorFromHitTest(hitTestResult, GetCurrentController()->ResourceService());
							if (cursor)
							{
								return cursor->GetSystemCursorType();
							}
						}
					}
				}
			}
		}
		return {};
	}

	void GuiRemoteGraphicsRenderTarget::StartRenderingOnNativeWindow()
	{
		CHECK_ERROR(hitTestResults.Count() == 0, L"vl::presentation::elements::GuiRemoteGraphicsRenderTarget::StartRenderingOnNativeWindow()#Internal error: hit test result stack is not cleared.");
		canvasSize = remote->remoteWindow.GetClientSize();
		clipperValidArea = GetClipper();
		renderingBatchId++;
		EnsureRequestedRenderersCreated();

		{
			remoteprotocol::ElementBeginRendering arguments;
			arguments.frameId = ++usedFrameIds;
			arguments.updatedElements = Ptr(new List<remoteprotocol::OrdinaryElementDescVariant>);

			if (needFullElementUpdateOnNextFrame)
			{
				for (auto renderer : renderers.Values())
				{
					renderer->SendUpdateElementMessages(true, *arguments.updatedElements.Obj());
					if (renderer->NeedUpdateMinSizeFromCache())
					{
						if (!renderersAskingForCache.Contains(renderer))
						{
							renderersAskingForCache.Add(renderer);
						}
					}
					renderer->ResetUpdated();
				}
				needFullElementUpdateOnNextFrame = false;
			}
			else
			{
				for (auto [id, renderer] : renderers)
				{
					if (renderer->IsUpdated())
					{
						renderer->SendUpdateElementMessages(false, *arguments.updatedElements.Obj());
						if (renderer->NeedUpdateMinSizeFromCache())
						{
							if (!renderersAskingForCache.Contains(renderer))
							{
								renderersAskingForCache.Add(renderer);
							}
						}
						renderer->ResetUpdated();
					}
				}
			}

			remote->remoteMessages.RequestRendererBeginRendering(arguments);
		}
	}

	RenderTargetFailure GuiRemoteGraphicsRenderTarget::StopRenderingOnNativeWindow()
	{
		CHECK_ERROR(hitTestResults.Count() == 0, L"vl::presentation::elements::GuiRemoteGraphicsRenderTarget::StartRenderingOnNativeWindow()#Internal error: hit test result stack is not cleared.");
		vint idRendering = remote->remoteMessages.RequestRendererEndRendering();
		bool disconnected = false;
		remote->remoteMessages.Submit(disconnected);
		if (disconnected) return RenderTargetFailure::None;
		auto measuring = remote->remoteMessages.RetrieveRendererEndRendering(idRendering);

		bool minSizeChanged = false;

		if (measuring.fontHeights)
		{
			for (auto&& fontHeight : *measuring.fontHeights.Obj())
			{
				auto key = Tuple(fontHeight.fontFamily, fontHeight.fontSize);
				if (!fontHeights.Keys().Contains(key))
				{
					fontHeights.Add(key, fontHeight.height);
				}
			}
		}

		if (measuring.createdImages)
		{
			for (auto&& imageMetadata : *measuring.createdImages.Obj())
			{
				auto image = remote->imageService.GetImage(imageMetadata.id);
				image->UpdateFromImageMetadata(imageMetadata);
			}
		}

		if (measuring.fontHeights || measuring.createdImages)
		{
			// TODO: (enumerable) foreach:indexed(alterable(reversed))
			for (vint i = renderersAskingForCache.Count() - 1; i >= 0; i--)
			{
				auto renderer = renderersAskingForCache[i];
				auto oldMinSize = renderer->GetRenderer()->GetMinSize();
				renderer->TryFetchMinSizeFromCache();
				if (renderer->IsRenderedInLastBatch() && oldMinSize != renderer->GetRenderer()->GetMinSize())
				{
					minSizeChanged = true;
				}
				if (!renderer->NeedUpdateMinSizeFromCache())
				{
					renderersAskingForCache.RemoveAt(i);
				}
			}
		}

		if (measuring.minSizes)
		{
			for (auto&& minSize : *measuring.minSizes.Obj())
			{
				vint index = renderers.Keys().IndexOf(minSize.id);
				if (index != -1)
				{
					auto renderer = renderers.Values()[index];
					auto oldMinSize = renderer->GetRenderer()->GetMinSize();
					renderer->UpdateMinSize(minSize.minSize);
					if (renderer->IsRenderedInLastBatch() && oldMinSize != renderer->GetRenderer()->GetMinSize())
					{
						minSizeChanged = true;
					}
				}
			}
		}

		if (measuring.inlineObjectBounds)
		{
			for (auto&& inlineObjectBound : *measuring.inlineObjectBounds.Obj())
			{
				vint index = paragraphs.Keys().IndexOf(inlineObjectBound.elementId);
				if (index != -1)
				{
					auto paragraph = paragraphs.Values()[index];
					paragraph->SetInlineObjectBounds(inlineObjectBound.callbackId, inlineObjectBound.bounds);
				}
			}
		}

		if (minSizeChanged)
		{
			hostedController->RequestRefresh();
		}

		if (canvasSize == remote->remoteWindow.GetClientSize())
		{
			return RenderTargetFailure::None;
		}
		else
		{
			return RenderTargetFailure::ResizeWhileRendering;
		}
	}

	void GuiRemoteGraphicsRenderTarget::HostedRenderingIdle()
	{
		remote->remoteMessages.RequestRendererIdle();
	}

	Size GuiRemoteGraphicsRenderTarget::GetCanvasSize()
	{
		return remote->remoteWindow.Convert(canvasSize);
	}

	void GuiRemoteGraphicsRenderTarget::AfterPushedClipper(Rect clipper, Rect validArea, reflection::DescriptableObject* generator)
	{
		clipperValidArea = validArea;
		auto hitTestResult = GetHitTestResultFromGenerator(generator);
		auto cursor = GetCursorFromGenerator(generator);

		remoteprotocol::ElementBoundary arguments;
		if (hitTestResult != INativeWindowListener::NoDecision)
		{
			if (hitTestResults.Count() == 0 || hitTestResults[hitTestResults.Count() - 1] != hitTestResult)
			{
				arguments.hitTestResult = hitTestResult;
			}
			hitTestResults.Add(hitTestResult);
		}
		if (cursor)
		{
			if (cursors.Count() == 0 || cursors[cursors.Count() - 1] != cursor.Value())
			{
				arguments.cursor = cursor.Value();
			}
			cursors.Add(cursor.Value());
		}

		if (arguments.hitTestResult || arguments.cursor)
		{
			// GetHitTestResultFromGenerator or GetCursorFromGenerator ensures generator must be a composition
			auto composition = dynamic_cast<GuiGraphicsComposition*>(generator);
			if (composition->remoteId == -1)
			{
				composition->remoteId = ++usedCompositionIds;
			}
			arguments.id = composition->remoteId;
			arguments.bounds = clipper;
			arguments.areaClippedBySelf = validArea;
			remote->remoteMessages.RequestRendererBeginBoundary(arguments);
		}
	}

	void GuiRemoteGraphicsRenderTarget::AfterPushedClipperAndBecameInvalid(Rect clipper, reflection::DescriptableObject* generator)
	{
		clipperValidArea.Reset();
	}

	void GuiRemoteGraphicsRenderTarget::AfterPoppedClipperAndBecameValid(Rect validArea, bool clipperExists, reflection::DescriptableObject* generator)
	{
		clipperValidArea = validArea;
	}

	void GuiRemoteGraphicsRenderTarget::AfterPoppedClipper(Rect validArea, bool clipperExists, reflection::DescriptableObject* generator)
	{
		clipperValidArea = validArea;
		auto hitTestResult = GetHitTestResultFromGenerator(generator);
		auto cursor = GetCursorFromGenerator(generator);
		bool needEndBoundary = false;

		if (hitTestResult != INativeWindowListener::NoDecision)
		{
			hitTestResults.RemoveAt(hitTestResults.Count() - 1);
			if (hitTestResults.Count() == 0 || hitTestResults[hitTestResults.Count() - 1] != hitTestResult)
			{
				needEndBoundary = true;
			}
		}
		if (cursor)
		{
			cursors.RemoveAt(cursors.Count() - 1);
			if (cursors.Count() == 0 || cursors[cursors.Count() - 1] != cursor.Value())
			{
				needEndBoundary = true;
			}
		}

		if (needEndBoundary)
		{
			remote->remoteMessages.RequestRendererEndBoundary();
		}
	}

	GuiRemoteGraphicsRenderTarget::GuiRemoteGraphicsRenderTarget(GuiRemoteController* _remote, GuiHostedController* _hostedController)
		: remote(_remote)
		, hostedController(_hostedController)
	{
	}

	GuiRemoteGraphicsRenderTarget::~GuiRemoteGraphicsRenderTarget()
	{
	}

	void GuiRemoteGraphicsRenderTarget::EnsureRequestedRenderersCreated()
	{
		if (destroyedRenderers.Count() > 0)
		{
			auto ids = Ptr(new List<vint>);
			CopyFrom(*ids.Obj(), destroyedRenderers);
			destroyedRenderers.Clear();
			remote->remoteMessages.RequestRendererDestroyed(ids);
		}

		if (createdRenderers.Count() > 0 || pendingParagraphCreations.Count() > 0)
		{
			auto ids = Ptr(new List<remoteprotocol::RendererCreation>);
			for (auto id : createdRenderers)
			{
				ids->Add({ id,renderers[id]->GetRendererType() });
			}
			CopyFrom(*ids.Obj(), pendingParagraphCreations, true);
			createdRenderers.Clear();
			pendingParagraphCreations.Clear();
			remote->remoteMessages.RequestRendererCreated(ids);
		}
	}

	void GuiRemoteGraphicsRenderTarget::OnControllerConnect()
	{
		fontHeights.Clear();
		renderersAskingForCache.Clear();

		if (renderers.Count() > 0 || paragraphs.Count() > 0)
		{
			auto ids = Ptr(new List<remoteprotocol::RendererCreation>);
			for (auto renderer : renderers.Values())
			{
				ids->Add({ renderer->GetID(),renderer->GetRendererType() });
				renderer->NotifyMinSizeCacheInvalidated();
			}
			for (auto paragraph : paragraphs.Values())
			{
				ids->Add({ paragraph->GetParagraphId(),remoteprotocol::RendererType::DocumentParagraph });
			}
			createdRenderers.Clear();
			pendingParagraphCreations.Clear();
			remote->remoteMessages.RequestRendererCreated(ids);
		}

		needFullElementUpdateOnNextFrame = true;

		for (auto paragraph : paragraphs.Values())
		{
			paragraph->ResetRemoteParagraphSyncState();
			paragraph->EnsureRemoteParagraphSynced();
		}
	}

	void GuiRemoteGraphicsRenderTarget::OnControllerDisconnect()
	{
	}

	GuiRemoteMessages& GuiRemoteGraphicsRenderTarget::GetRemoteMessages()
	{
		return remote->remoteMessages;
	}

	vint GuiRemoteGraphicsRenderTarget::AllocateNewElementId()
	{
		return ++usedElementIds;
	}

	void GuiRemoteGraphicsRenderTarget::RegisterRenderer(elements_remoteprotocol::IGuiRemoteProtocolElementRender* renderer)
	{
		vint id = renderer->GetID();
		if (!createdRenderers.Contains(id))
		{
			renderers.Add(id, renderer);
			createdRenderers.Add(id);
		}
	}

	void GuiRemoteGraphicsRenderTarget::UnregisterRenderer(elements_remoteprotocol::IGuiRemoteProtocolElementRender* renderer)
	{
		vint id = renderer->GetID();
		renderers.Remove(id);
		renderersAskingForCache.Remove(renderer);

		vint index = createdRenderers.IndexOf(id);
		if (index == -1)
		{
			if (!destroyedRenderers.Contains(id))
			{
				destroyedRenderers.Add(id);
			}
		}
		else
		{
			createdRenderers.RemoveAt(index);
		}
	}

	Rect GuiRemoteGraphicsRenderTarget::GetClipperValidArea()
	{
		return clipperValidArea.Value();
	}

	GuiRemoteGraphicsParagraph* GuiRemoteGraphicsRenderTarget::GetParagraph(vint id)
	{
		vint index = paragraphs.Keys().IndexOf(id);
		return index == -1 ? nullptr : paragraphs.Values()[index];
	}

	void GuiRemoteGraphicsRenderTarget::RegisterParagraph(GuiRemoteGraphicsParagraph* paragraph)
	{
		auto id = paragraph->GetParagraphId();
		if (!paragraphs.Keys().Contains(id))
		{
			paragraphs.Add(id, paragraph);
			pendingParagraphCreations.Add({ id,remoteprotocol::RendererType::DocumentParagraph });
		}
	}

	void GuiRemoteGraphicsRenderTarget::UnregisterParagraph(vint id)
	{
		vint index = paragraphs.Keys().IndexOf(id);
		if (index == -1)
		{
			return;
		}

		paragraphs.Remove(id);
		{
			for (vint i = pendingParagraphCreations.Count() - 1; i >= 0; i--)
			{
				if (pendingParagraphCreations[i].id == id)
				{
					pendingParagraphCreations.RemoveAt(i);
					return;
				}
			}
		}
		if (!destroyedRenderers.Contains(id))
		{
			destroyedRenderers.Add(id);
		}
	}

/***********************************************************************
GuiRemoteGraphicsResourceManager
***********************************************************************/

	Ptr<IGuiGraphicsParagraph> GuiRemoteGraphicsResourceManager::CreateParagraph(const WString& text, IGuiGraphicsRenderTarget* _renderTarget, IGuiGraphicsParagraphCallback* callback)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::GuiRemoteGraphicsResourceManager::CreateParagraph(const WString&, IGuiGraphicsRenderTarget*, IGuiGraphicsParagraphCallback*)#"
		CHECK_ERROR(&renderTarget == _renderTarget, ERROR_MESSAGE_PREFIX L"Unexpected render target object.");
		return Ptr(new GuiRemoteGraphicsParagraph(text, remote, this, &renderTarget, callback));
#undef ERROR_MESSAGE_PREFIX
	}

	GuiRemoteGraphicsResourceManager::GuiRemoteGraphicsResourceManager(GuiRemoteController* _remote, GuiHostedController* _hostedController)
		: remote(_remote)
		, renderTarget(_remote, _hostedController)
		, hostedController(_hostedController)
	{
		remote->resourceManager = this;
	}

	GuiRemoteGraphicsResourceManager::~GuiRemoteGraphicsResourceManager()
	{
	}

	void GuiRemoteGraphicsResourceManager::Initialize()
	{
		elements_remoteprotocol::GuiFocusRectangleElementRenderer::Register();
		elements_remoteprotocol::GuiRawElementRenderer::Register();
		elements_remoteprotocol::GuiSolidBorderElementRenderer::Register();
		elements_remoteprotocol::Gui3DBorderElementRenderer::Register();
		elements_remoteprotocol::Gui3DSplitterElementRenderer::Register();
		elements_remoteprotocol::GuiSolidBackgroundElementRenderer::Register();
		elements_remoteprotocol::GuiGradientBackgroundElementRenderer::Register();
		elements_remoteprotocol::GuiInnerShadowElementRenderer::Register();
		elements_remoteprotocol::GuiSolidLabelElementRenderer::Register();
		elements_remoteprotocol::GuiImageFrameElementRenderer::Register();
		elements_remoteprotocol::GuiPolygonElementRenderer::Register();
		elements::GuiDocumentElementRenderer::Register();
	}

	void GuiRemoteGraphicsResourceManager::Finalize()
	{
	}

	void GuiRemoteGraphicsResourceManager::OnControllerConnect()
	{
		renderTarget.OnControllerConnect();
		hostedController->RequestRefresh();
	}

	void GuiRemoteGraphicsResourceManager::OnControllerDisconnect()
	{
		renderTarget.OnControllerDisconnect();
	}

	IGuiGraphicsRenderTarget* GuiRemoteGraphicsResourceManager::GetRenderTarget(INativeWindow* window)
	{
		CHECK_ERROR(window == &remote->remoteWindow, L"vl::presentation::elements::GuiRemoteGraphicsResourceManager::GetRenderTarget(INativeWindow*)#GuiHostedController should call this function with the native window.");
		return &renderTarget;
	}

	void GuiRemoteGraphicsResourceManager::RecreateRenderTarget(INativeWindow* window)
	{
	}

	void GuiRemoteGraphicsResourceManager::ResizeRenderTarget(INativeWindow* window)
	{
	}

	IGuiGraphicsLayoutProvider* GuiRemoteGraphicsResourceManager::GetLayoutProvider()
	{
		return this;
	}

	Ptr<IGuiGraphicsElement> GuiRemoteGraphicsResourceManager::CreateRawElement()
	{
		return Ptr(elements_remoteprotocol::GuiRemoteRawElement::Create());
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEGRAPHICS_BASICELEMENTS.CPP
***********************************************************************/

namespace vl::presentation::elements_remoteprotocol
{
	using namespace collections;
	using namespace remoteprotocol;

/***********************************************************************
GuiRemoteRawElement
***********************************************************************/

	GuiRemoteRawElement::GuiRemoteRawElement()
	{
	}

/***********************************************************************
GuiRemoteProtocolElementRenderer
***********************************************************************/

#define RENDERER_TEMPLATE_HEADER	template<typename TElement, typename TRenderer, remoteprotocol::RendererType _RendererType>
#define RENDERER_CLASS_TYPE			GuiRemoteProtocolElementRenderer<TElement, TRenderer, _RendererType>

	RENDERER_TEMPLATE_HEADER
	void RENDERER_CLASS_TYPE::InitializeInternal()
	{
	}

	RENDERER_TEMPLATE_HEADER
	void RENDERER_CLASS_TYPE::FinalizeInternal()
	{
		if (GetGuiGraphicsResourceManager() && id != -1)
		{
			remoteRenderTarget->UnregisterRenderer(this);
			id = -1;
		}
	}

	RENDERER_TEMPLATE_HEADER
	void RENDERER_CLASS_TYPE::RenderTargetChangedInternal(GuiRemoteGraphicsRenderTarget* oldRenderTarget, GuiRemoteGraphicsRenderTarget* newRenderTarget)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements_remoteprotocol::GuiRemoteProtocolElementRenderer<TElement, TRenderer, RendererType>::RenderTargetChangedInternal(GuiRemoteGraphicsRenderTarget*, GuiRemoteGraphicsRenderTarget*)#"
		if (oldRenderTarget == newRenderTarget) return;
		if (newRenderTarget)
		{
			if (!remoteRenderTarget)
			{
				remoteRenderTarget = newRenderTarget;
			}
			else
			{
				CHECK_ERROR(remoteRenderTarget == newRenderTarget, ERROR_MESSAGE_PREFIX L"There should be only one global GuiRemoteGraphicsRenderTarget.");
			}
			if (id == -1)
			{
				id = newRenderTarget->AllocateNewElementId();
				newRenderTarget->RegisterRenderer(this);
			}
			updated = true;
			renderTargetChanged = true;
		}
#undef ERROR_MESSAGE_PREFIX
	}

	RENDERER_TEMPLATE_HEADER
	IGuiGraphicsRenderer* RENDERER_CLASS_TYPE::GetRenderer()
	{
		return this;
	}

	RENDERER_TEMPLATE_HEADER
	vint RENDERER_CLASS_TYPE::GetID()
	{
		return id;
	}

	RENDERER_TEMPLATE_HEADER
	remoteprotocol::RendererType RENDERER_CLASS_TYPE::GetRendererType()
	{
		return _RendererType;
	}

	RENDERER_TEMPLATE_HEADER
	bool RENDERER_CLASS_TYPE::IsUpdated()
	{
		return updated;
	}

	RENDERER_TEMPLATE_HEADER
	void RENDERER_CLASS_TYPE::ResetUpdated()
	{
		updated = false;
		renderTargetChanged = false;
	}

	RENDERER_TEMPLATE_HEADER
	bool RENDERER_CLASS_TYPE::IsRenderedInLastBatch()
	{
		return this->renderTarget && this->renderTarget->renderingBatchId == renderingBatchId;
	}

	RENDERER_TEMPLATE_HEADER
	bool RENDERER_CLASS_TYPE::NeedUpdateMinSizeFromCache()
	{
		return false;
	}

	RENDERER_TEMPLATE_HEADER
	void RENDERER_CLASS_TYPE::TryFetchMinSizeFromCache()
	{
		CHECK_FAIL(L"vl::presentation::elements_remoteprotocol::GuiRemoteProtocolElementRenderer<TElement, TRenderer, RendererType>::TryUpdateFromCache()#This function should not be called.");
	}

	RENDERER_TEMPLATE_HEADER
	void RENDERER_CLASS_TYPE::UpdateMinSize(Size size)
	{
		CHECK_FAIL(L"vl::presentation::elements_remoteprotocol::GuiRemoteProtocolElementRenderer<TElement, TRenderer, RendererType>::UpdateMinSize(Size)#This function should not be called.");
	}

	RENDERER_TEMPLATE_HEADER
	void RENDERER_CLASS_TYPE::NotifyMinSizeCacheInvalidated()
	{
	}

	RENDERER_TEMPLATE_HEADER
	void RENDERER_CLASS_TYPE::Render(Rect bounds)
	{
		remoteprotocol::ElementRendering arguments;
		arguments.id = id;
		arguments.bounds = bounds;
		arguments.areaClippedByParent = this->renderTarget->GetClipperValidArea();
		this->remoteRenderTarget->GetRemoteMessages().RequestRendererRenderElement(arguments);
		renderingBatchId = this->renderTarget->renderingBatchId;
	}

	RENDERER_TEMPLATE_HEADER
	void RENDERER_CLASS_TYPE::OnElementStateChanged()
	{
		updated = true;
	}


#undef RENDERER_CLASS_TYPE
#undef RENDERER_TEMPLATE_HEADER

/***********************************************************************
GuiFocusRectangleElementRenderer
***********************************************************************/

	GuiFocusRectangleElementRenderer::GuiFocusRectangleElementRenderer()
	{
	}
	
	bool GuiFocusRectangleElementRenderer::IsUpdated()
	{
		// there is no properties for this element
		return false;
	}

	void GuiFocusRectangleElementRenderer::ResetUpdated()
	{
		// nothing to update
	}

	void GuiFocusRectangleElementRenderer::OnElementStateChanged()
	{
		// nothing to update
	}

	void GuiFocusRectangleElementRenderer::SendUpdateElementMessages(bool fullContent, collections::List<remoteprotocol::OrdinaryElementDescVariant>& updatedElements)
	{
		// nothing to update
	}

/***********************************************************************
GuiRawElementRenderer
***********************************************************************/

	GuiRawElementRenderer::GuiRawElementRenderer()
	{
	}
	
	bool GuiRawElementRenderer::IsUpdated()
	{
		// there is no properties for this element
		return false;
	}

	void GuiRawElementRenderer::ResetUpdated()
	{
		// nothing to update
	}

	void GuiRawElementRenderer::OnElementStateChanged()
	{
		// nothing to update
	}

	void GuiRawElementRenderer::SendUpdateElementMessages(bool fullContent, collections::List<remoteprotocol::OrdinaryElementDescVariant>& updatedElements)
	{
		// nothing to update
	}

/***********************************************************************
GuiSolidBorderElementRenderer
***********************************************************************/

	GuiSolidBorderElementRenderer::GuiSolidBorderElementRenderer()
	{
	}

	void GuiSolidBorderElementRenderer::SendUpdateElementMessages(bool fullContent, collections::List<remoteprotocol::OrdinaryElementDescVariant>& updatedElements)
	{
		ElementDesc_SolidBorder arguments;
		arguments.id = id;
		arguments.borderColor = element->GetColor();
		arguments.shape = element->GetShape();
		updatedElements.Add(remoteprotocol::OrdinaryElementDescVariant(arguments));
	}

/***********************************************************************
Gui3DBorderElementRenderer
***********************************************************************/

	Gui3DBorderElementRenderer::Gui3DBorderElementRenderer()
	{
	}

	void Gui3DBorderElementRenderer::SendUpdateElementMessages(bool fullContent, collections::List<remoteprotocol::OrdinaryElementDescVariant>& updatedElements)
	{
		ElementDesc_SinkBorder arguments;
		arguments.id = id;
		arguments.leftTopColor = element->GetColor1();
		arguments.rightBottomColor = element->GetColor2();
		updatedElements.Add(remoteprotocol::OrdinaryElementDescVariant(arguments));
	}

/***********************************************************************
Gui3DSplitterElementRenderer
***********************************************************************/

	Gui3DSplitterElementRenderer::Gui3DSplitterElementRenderer()
	{
	}

	void Gui3DSplitterElementRenderer::Render(Rect bounds)
	{
		switch (element->GetDirection())
		{
		case Gui3DSplitterElement::Horizontal:
			if (bounds.Height() < 2)
			{
				auto y = bounds.y1 + bounds.Height() / 2 - 1;
				bounds.y1 = y;
				bounds.y2 = y + 2;
			}
			break;
		case Gui3DSplitterElement::Vertical:
			if (bounds.Width() < 2)
			{
				auto x = bounds.x1 + bounds.Width() / 2 - 1;
				bounds.x1 = x;
				bounds.x2 = x + 2;
			}
			break;
		}

		GuiRemoteProtocolElementRenderer<Gui3DSplitterElement, Gui3DSplitterElementRenderer, remoteprotocol::RendererType::SinkSplitter>::Render(bounds);
	}

	void Gui3DSplitterElementRenderer::SendUpdateElementMessages(bool fullContent, collections::List<remoteprotocol::OrdinaryElementDescVariant>& updatedElements)
	{
		ElementDesc_SinkSplitter arguments;
		arguments.id = id;
		arguments.leftTopColor = element->GetColor1();
		arguments.rightBottomColor = element->GetColor2();
		arguments.direction = element->GetDirection();
		updatedElements.Add(remoteprotocol::OrdinaryElementDescVariant(arguments));
	}

/***********************************************************************
GuiSolidBackgroundElementRenderer
***********************************************************************/

	GuiSolidBackgroundElementRenderer::GuiSolidBackgroundElementRenderer()
	{
	}

	void GuiSolidBackgroundElementRenderer::SendUpdateElementMessages(bool fullContent, collections::List<remoteprotocol::OrdinaryElementDescVariant>& updatedElements)
	{
		ElementDesc_SolidBackground arguments;
		arguments.id = id;
		arguments.backgroundColor = element->GetColor();
		arguments.shape = element->GetShape();
		updatedElements.Add(remoteprotocol::OrdinaryElementDescVariant(arguments));
	}

/***********************************************************************
GuiGradientBackgroundElementRenderer
***********************************************************************/

	GuiGradientBackgroundElementRenderer::GuiGradientBackgroundElementRenderer()
	{
	}

	void GuiGradientBackgroundElementRenderer::SendUpdateElementMessages(bool fullContent, collections::List<remoteprotocol::OrdinaryElementDescVariant>& updatedElements)
	{
		ElementDesc_GradientBackground arguments;
		arguments.id = id;
		arguments.leftTopColor = element->GetColor1();
		arguments.rightBottomColor = element->GetColor2();
		arguments.direction = element->GetDirection();
		arguments.shape = element->GetShape();
		updatedElements.Add(remoteprotocol::OrdinaryElementDescVariant(arguments));
	}

/***********************************************************************
GuiInnerShadowElementRenderer
***********************************************************************/

	GuiInnerShadowElementRenderer::GuiInnerShadowElementRenderer()
	{
	}

	void GuiInnerShadowElementRenderer::SendUpdateElementMessages(bool fullContent, collections::List<remoteprotocol::OrdinaryElementDescVariant>& updatedElements)
	{
		ElementDesc_InnerShadow arguments;
		arguments.id = id;
		arguments.shadowColor = element->GetColor();
		arguments.thickness = element->GetThickness();
		updatedElements.Add(remoteprotocol::OrdinaryElementDescVariant(arguments));
	}

/***********************************************************************
GuiSolidLabelElementRenderer
***********************************************************************/

	GuiSolidLabelElementRenderer::MeasuringRequest GuiSolidLabelElementRenderer::GetMeasuringRequest()
	{
		if (element->GetEllipse())
		{
			return ElementSolidLabelMeasuringRequest::FontHeight;
		}
		else if (element->GetWrapLine() && !element->GetWrapLineHeightCalculation())
		{
			return {};
		}
		else
		{
			return ElementSolidLabelMeasuringRequest::TotalSize;
		}
	}

	bool GuiSolidLabelElementRenderer::IsNeedFontHeight(MeasuringRequest request)
	{
		return request && request.Value() == ElementSolidLabelMeasuringRequest::FontHeight;
	}

	GuiSolidLabelElementRenderer::GuiSolidLabelElementRenderer()
	{
		minSize = { 1,1 };
	}

	bool GuiSolidLabelElementRenderer::NeedUpdateMinSizeFromCache()
	{
		return needFontHeight;
	}

	void GuiSolidLabelElementRenderer::TryFetchMinSizeFromCache()
	{
		if (needFontHeight)
		{
			vint index = renderTarget->fontHeights.Keys().IndexOf({ lastFont.fontFamily,lastFont.size });
			if (index != -1)
			{
				needFontHeight = false;
				vint size = renderTarget->fontHeights.Values()[index];
				UpdateMinSize({ size,size });
			}
		}
	}

	void GuiSolidLabelElementRenderer::UpdateMinSize(Size size)
	{
		minSize = size;
		if (minSize.x < 1)minSize.x = 1;
		if (minSize.y < 1)minSize.y = 1;
	}

	void GuiSolidLabelElementRenderer::NotifyMinSizeCacheInvalidated()
	{
		OnElementStateChanged();
		auto request = GetMeasuringRequest();
		needFontHeight = IsNeedFontHeight(request);
	}

	void GuiSolidLabelElementRenderer::SendUpdateElementMessages(bool fullContent, collections::List<remoteprotocol::OrdinaryElementDescVariant>& updatedElements)
	{
		ElementDesc_SolidLabel arguments;
		arguments.id = id;
		arguments.textColor = element->GetColor();
		arguments.wrapLine = element->GetWrapLine();
		arguments.wrapLineHeightCalculation = element->GetWrapLineHeightCalculation();
		arguments.ellipse = element->GetEllipse();
		arguments.multiline = element->GetMultiline();

		switch (element->GetHorizontalAlignment())
		{
		case Alignment::Left:
			arguments.horizontalAlignment = ElementHorizontalAlignment::Left;
			break;
		case Alignment::Right:
			arguments.horizontalAlignment = ElementHorizontalAlignment::Right;
			break;
		default:
			arguments.horizontalAlignment = ElementHorizontalAlignment::Center;
		}

		switch (element->GetVerticalAlignment())
		{
		case Alignment::Top:
			arguments.verticalAlignment = ElementVerticalAlignment::Top;
			break;
		case Alignment::Bottom:
			arguments.verticalAlignment = ElementVerticalAlignment::Bottom;
			break;
		default:
			arguments.verticalAlignment = ElementVerticalAlignment::Center;
		}

		auto elementFont = element->GetFont();
		auto elementText = element->GetText();
		if (elementFont.fontFamily == WString::Empty)
		{
			elementFont = GetCurrentController()->ResourceService()->GetDefaultFont();
		}

		if (renderTargetChanged || fullContent || lastFont != elementFont)
		{
			arguments.font = elementFont;
		}

		if (renderTargetChanged || fullContent || lastText != elementText)
		{
			arguments.text = elementText;
		}

		lastFont = elementFont;
		lastText = elementText;
		arguments.measuringRequest = GetMeasuringRequest();
		if ((needFontHeight = IsNeedFontHeight(arguments.measuringRequest)))
		{
			TryFetchMinSizeFromCache();
			if (!needFontHeight)
			{
				arguments.measuringRequest.Reset();
			}
		}

		updatedElements.Add(remoteprotocol::OrdinaryElementDescVariant(arguments));
	}

/***********************************************************************
GuiImageFrameElementRenderer
***********************************************************************/

	GuiRemoteGraphicsImage* GuiImageFrameElementRenderer::GetRemoteImage()
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements_remoteprotocol::GuiImageFrameElementRenderer::GetRemoteImage()#"
		if (element && element->GetImage())
		{
			auto image = dynamic_cast<GuiRemoteGraphicsImage*>(element->GetImage().Obj());
			CHECK_ERROR(image, ERROR_MESSAGE_PREFIX L"Only INativeImage that created from GetCurrentController()->ImageService() is supported.");
			return image;
		}
		return nullptr;
#undef ERROR_MESSAGE_PREFIX
	}

	void GuiImageFrameElementRenderer::UpdateMinSizeFromImage(GuiRemoteGraphicsImage* image)
	{
		needUpdateSize = true;
		if (!image || element->GetStretch())
		{
			minSize = { 0,0 };
			needUpdateSize = false;
		}
		else if (image->status == GuiRemoteGraphicsImage::MetadataStatus::Retrived)
		{
			if (0 <= element->GetFrameIndex() && element->GetFrameIndex() < image->GetFrameCount())
			{
				minSize = image->GetFrame(element->GetFrameIndex())->GetSize();
			}
			else
			{
				minSize = { 0,0 };
			}
			needUpdateSize = false;
		}
	}

	GuiImageFrameElementRenderer::GuiImageFrameElementRenderer()
	{
	}

	bool GuiImageFrameElementRenderer::NeedUpdateMinSizeFromCache()
	{
		return needUpdateSize;
	}

	void GuiImageFrameElementRenderer::TryFetchMinSizeFromCache()
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements_remoteprotocol::GuiImageFrameElementRenderer::TryFetchMinSizeFromCache()#"
		auto image = GetRemoteImage();
		if (!image || image->status != GuiRemoteGraphicsImage::MetadataStatus::Retrived)
		{
			return;
		}
		UpdateMinSizeFromImage(image);
		needUpdateSize = false;
#undef ERROR_MESSAGE_PREFIX
	}

	void GuiImageFrameElementRenderer::SendUpdateElementMessages(bool fullContent, collections::List<remoteprotocol::OrdinaryElementDescVariant>& updatedElements)
	{
		auto image = GetRemoteImage();
		if (image)
		{
			needUpdateSize = true;
			if (fullContent)
			{
				if (fullContent && image->status == GuiRemoteGraphicsImage::MetadataStatus::Retrived)
				{
					image->status = GuiRemoteGraphicsImage::MetadataStatus::Uninitialized;
				}
			}
			else
			{
				if (image->status == GuiRemoteGraphicsImage::MetadataStatus::Uninitialized)
				{
					image->EnsureMetadata();
				}
			}
			if (image->status == GuiRemoteGraphicsImage::MetadataStatus::Retrived)
			{
				UpdateMinSizeFromImage(image);
				renderTargetChanged = false;
			}
		}

		remoteprotocol::ElementDesc_ImageFrame arguments;
		arguments.id = id;
		if (image) arguments.imageId = image->id;
		arguments.imageFrame = element->GetFrameIndex();
		arguments.stretch = element->GetStretch();
		arguments.enabled = element->GetEnabled();

		switch (element->GetHorizontalAlignment())
		{
		case Alignment::Left:
			arguments.horizontalAlignment = ElementHorizontalAlignment::Left;
			break;
		case Alignment::Right:
			arguments.horizontalAlignment = ElementHorizontalAlignment::Right;
			break;
		default:
			arguments.horizontalAlignment = ElementHorizontalAlignment::Center;
		}

		switch (element->GetVerticalAlignment())
		{
		case Alignment::Top:
			arguments.verticalAlignment = ElementVerticalAlignment::Top;
			break;
		case Alignment::Bottom:
			arguments.verticalAlignment = ElementVerticalAlignment::Bottom;
			break;
		default:
			arguments.verticalAlignment = ElementVerticalAlignment::Center;
		}

		if ((renderTargetChanged || needUpdateSize) && image)
		{
			arguments.imageCreation = image->GenerateImageCreation();
		}

		updatedElements.Add(remoteprotocol::OrdinaryElementDescVariant(arguments));
	}

/***********************************************************************
GuiPolygonElementRenderer
***********************************************************************/

	GuiPolygonElementRenderer::GuiPolygonElementRenderer()
	{
	}

	void GuiPolygonElementRenderer::SendUpdateElementMessages(bool fullContent, collections::List<remoteprotocol::OrdinaryElementDescVariant>& updatedElements)
	{
		minSize = element->GetSize();

		ElementDesc_Polygon arguments;
		arguments.id = id;
		arguments.size = element->GetSize();
		arguments.borderColor = element->GetBorderColor();
		arguments.backgroundColor = element->GetBackgroundColor();
		arguments.points = Ptr(new List<Point>);
		CopyFrom(*arguments.points.Obj(), element->GetPointsArray());
		updatedElements.Add(remoteprotocol::OrdinaryElementDescVariant(arguments));
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEGRAPHICS_DOCUMENT.CPP
***********************************************************************/

namespace vl::presentation::elements
{
	using namespace collections;

/***********************************************************************
GuiRemoteCaretCache
***********************************************************************/

	GuiRemoteCaretCache::GuiRemoteCaretCache(const WString& text, remoteprotocol::CharacterEncoding encoding)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::GuiRemoteCaretCache::GuiRemoteCaretCache(const WString&, remoteprotocol::CharacterEncoding)#"
		CHECK_ERROR(
			encoding == remoteprotocol::CharacterEncoding::UTF8 ||
			encoding == remoteprotocol::CharacterEncoding::UTF16 ||
			encoding == remoteprotocol::CharacterEncoding::UTF32,
			ERROR_MESSAGE_PREFIX L"Unknown character encoding.");

		List<vint> nativeMapping;
		List<vint> remoteMapping;
		vint nativePos = 0;
		vint remotePos = 0;
		while (nativePos < text.Length())
		{
			char32_t scalar = 0;
			auto nativeLength = vl::encoding::UtfConversion<wchar_t>::To32(
				text.Buffer() + nativePos,
				text.Length() - nativePos,
				scalar);

			vint remoteLength = 1;
			if (nativeLength == -1)
			{
				nativeLength = 1;
			}
			else
			{
				switch (encoding)
				{
				case remoteprotocol::CharacterEncoding::UTF8:
					{
						char8_t buffer[vl::encoding::UtfConversion<char8_t>::BufferLength];
						remoteLength = vl::encoding::UtfConversion<char8_t>::From32(scalar, buffer);
					}
					break;
				case remoteprotocol::CharacterEncoding::UTF16:
					{
						char16_t buffer[vl::encoding::UtfConversion<char16_t>::BufferLength];
						remoteLength = vl::encoding::UtfConversion<char16_t>::From32(scalar, buffer);
					}
					break;
				case remoteprotocol::CharacterEncoding::UTF32:
					remoteLength = 1;
					break;
				}
				if (remoteLength == -1)
				{
					remoteLength = 1;
				}
			}

			for (vint i = 0; i < nativeLength; i++)
			{
				nativeMapping.Add(remotePos);
			}
			for (vint i = 0; i < remoteLength; i++)
			{
				remoteMapping.Add(nativePos);
			}
			nativePos += nativeLength;
			remotePos += remoteLength;
		}
		nativeMapping.Add(remotePos);
		remoteMapping.Add(nativePos);
		CopyFrom(nativeToRemote, nativeMapping);
		CopyFrom(remoteToNative, remoteMapping);
#undef ERROR_MESSAGE_PREFIX
	}

/***********************************************************************
GuiRemoteGraphicsParagraph
***********************************************************************/

	GuiRemoteGraphicsParagraph::GuiRemoteGraphicsParagraph(const WString& _text, GuiRemoteController* _remote, GuiRemoteGraphicsResourceManager* _resourceManager, GuiRemoteGraphicsRenderTarget* _renderTarget, IGuiGraphicsParagraphCallback* _callback)
		: text(_text)
		, remote(_remote)
		, resourceManager(_resourceManager)
		, renderTarget(_renderTarget)
		, callback(_callback)
	{
		if (renderTarget)
		{
			id = renderTarget->AllocateNewElementId();
			renderTarget->RegisterParagraph(this);
		}
	}

	GuiRemoteGraphicsParagraph::~GuiRemoteGraphicsParagraph()
	{
		if (renderTarget && id != -1)
		{
			renderTarget->UnregisterParagraph(id);
			id = -1;
		}
	}

	vint GuiRemoteGraphicsParagraph::GetParagraphId() const
	{
		return id;
	}

	bool GuiRemoteGraphicsParagraph::EnsureRemoteParagraphSynced()
	{
		if (!needUpdate)
		{
			return id != -1;
		}

		if (id == -1 || !renderTarget)
		{
			return false;
		}

		renderTarget->EnsureRequestedRenderersCreated();

		stagedRuns.Clear();
		MergeRuns(textRuns, inlineObjectRuns, stagedRuns);

		remoteprotocol::ElementDesc_DocumentParagraph desc;
		if (!remoteParagraphCreated)
		{
			desc.text = text;
		}

		switch (paragraphAlignment)
		{
		case Alignment::Right:
			desc.alignment = remoteprotocol::ElementHorizontalAlignment::Right;
			break;
		case Alignment::Center:
			desc.alignment = remoteprotocol::ElementHorizontalAlignment::Center;
			break;
		default:
			desc.alignment = remoteprotocol::ElementHorizontalAlignment::Left;
			break;
		}

		desc.wrapLine = wrapLine;
		desc.maxWidth = maxWidth;
		desc.id = id;
		DiffRuns(committedRuns, stagedRuns, desc);
		for (vint i = 0; i < desc.runsDiff->Count(); i++)
		{
			auto&& run = (*desc.runsDiff.Obj())[i];
			run.caretBegin = NativeTextPosToRemoteTextPos(run.caretBegin);
			run.caretEnd = NativeTextPosToRemoteTextPos(run.caretEnd);
		}

		auto& messages = renderTarget->GetRemoteMessages();
		vint requestId = messages.RequestRendererUpdateElement_DocumentParagraph(desc);
		bool disconnected = false;
		messages.Submit(disconnected);
		if (disconnected)
		{
			return false;
		}

		{
			auto response = messages.RetrieveRendererUpdateElement_DocumentParagraph(requestId);
			cachedSize = response.documentSize;
			if (desc.removedInlineObjects)
			{
				for (auto callbackId : *desc.removedInlineObjects.Obj())
				{
					cachedInlineObjectBounds.Remove(callbackId);
				}
			}
		}
		committedRuns = std::move(stagedRuns);
		remoteParagraphCreated = true;
		needUpdate = false;

		if (needUpdateCaretBoundsCache)
		{
			needUpdateCaretBoundsCache = false;
			cachedCaretBounds = {};
		}
		return true;
	}

	void GuiRemoteGraphicsParagraph::ResetRemoteParagraphSyncState()
	{
		committedRuns.Clear();
		cachedInlineObjectBounds.Clear();
		cachedCaretBounds = {};
		remoteParagraphCreated = false;
		needUpdate = true;
		needUpdateCaretBoundsCache = true;
	}

	bool GuiRemoteGraphicsParagraph::TryBuildCaretRange(vint start, vint length, CaretRange& range)
	{
		if (length <= 0 || start < 0 || start + length > text.Length())
		{
			return false;
		}
		range.caretBegin = start;
		range.caretEnd = start + length;
		return true;
	}

	void GuiRemoteGraphicsParagraph::MarkParagraphDirty(bool invalidateSize, bool invalidateCaretBoundsCache)
	{
		needUpdate = true;
		if (invalidateSize)
		{
			cachedSize = Size(0, 0);
		}
		if (invalidateCaretBoundsCache)
		{
			needUpdateCaretBoundsCache = true;
		}
	}

	void GuiRemoteGraphicsParagraph::SetInlineObjectBounds(vint callbackId, const Rect& bounds)
	{
		cachedInlineObjectBounds.Set(callbackId, bounds);
	}

	GuiRemoteCaretCache* GuiRemoteGraphicsParagraph::GetCaretCache()
	{
		auto encoding = remote->GetGlobalConfig().documentCaretFromEncoding;
#if defined VCZH_WCHAR_UTF16
		constexpr auto nativeEncoding = remoteprotocol::CharacterEncoding::UTF16;
#elif defined VCZH_WCHAR_UTF32
		constexpr auto nativeEncoding = remoteprotocol::CharacterEncoding::UTF32;
#endif
		if (encoding == nativeEncoding)
		{
			return nullptr;
		}

		auto index = caretCaches.Keys().IndexOf(encoding);
		if (index == -1)
		{
			auto cache = Ptr(new GuiRemoteCaretCache(text, encoding));
			caretCaches.Add(encoding, cache);
			return cache.Obj();
		}
		return caretCaches.Values()[index].Obj();
	}

	vint GuiRemoteGraphicsParagraph::NativeTextPosToRemoteTextPos(vint textPos)
	{
		auto cache = GetCaretCache();
		return cache ? cache->nativeToRemote[textPos] : textPos;
	}

	vint GuiRemoteGraphicsParagraph::RemoteTextPosToNativeTextPos(vint textPos)
	{
		auto cache = GetCaretCache();
		return cache ? cache->remoteToNative[textPos] : textPos;
	}

	IGuiGraphicsLayoutProvider* GuiRemoteGraphicsParagraph::GetProvider()
	{
		return resourceManager;
	}

	IGuiGraphicsRenderTarget* GuiRemoteGraphicsParagraph::GetRenderTarget()
	{
		return renderTarget;
	}

	bool GuiRemoteGraphicsParagraph::GetWrapLine()
	{
		return wrapLine;
	}

	void GuiRemoteGraphicsParagraph::SetWrapLine(bool value)
	{
		if (wrapLine != value)
		{
			wrapLine = value;
			MarkParagraphDirty(true, true);
		}
	}

	vint GuiRemoteGraphicsParagraph::GetMaxWidth()
	{
		return maxWidth;
	}

	void GuiRemoteGraphicsParagraph::SetMaxWidth(vint value)
	{
		if (maxWidth != value)
		{
			maxWidth = value;
			if (wrapLine)
			{
				MarkParagraphDirty(true, true);
			}
		}
	}

	Alignment GuiRemoteGraphicsParagraph::GetParagraphAlignment()
	{
		return paragraphAlignment;
	}

	void GuiRemoteGraphicsParagraph::SetParagraphAlignment(Alignment value)
	{
		if (paragraphAlignment != value)
		{
			paragraphAlignment = value;
			MarkParagraphDirty(true, true);
		}
	}

	bool GuiRemoteGraphicsParagraph::SetFont(vint start, vint length, const WString& value)
	{
		CaretRange range;
		if (!TryBuildCaretRange(start, length, range)) return false;

		DocumentTextRunPropertyOverrides overrides;
		overrides.fontFamily = value;
		bool updated = AddTextRun(textRuns, range, overrides);
		MarkParagraphDirty(true, updated);
		return true;
	}

	bool GuiRemoteGraphicsParagraph::SetSize(vint start, vint length, vint value)
	{
		CaretRange range;
		if (!TryBuildCaretRange(start, length, range)) return false;

		DocumentTextRunPropertyOverrides overrides;
		overrides.size = value;
		bool updated = AddTextRun(textRuns, range, overrides);
		MarkParagraphDirty(true, updated);
		return true;
	}

	bool GuiRemoteGraphicsParagraph::SetStyle(vint start, vint length, TextStyle value)
	{
		CaretRange range;
		if (!TryBuildCaretRange(start, length, range)) return false;

		DocumentTextRunPropertyOverrides overrides;
		overrides.textStyle = value;
		bool updated = AddTextRun(textRuns, range, overrides);
		MarkParagraphDirty(true, updated);
		return true;
	}

	bool GuiRemoteGraphicsParagraph::SetColor(vint start, vint length, Color value)
	{
		CaretRange range;
		if (!TryBuildCaretRange(start, length, range)) return false;

		DocumentTextRunPropertyOverrides overrides;
		overrides.textColor = value;
		AddTextRun(textRuns, range, overrides);
		MarkParagraphDirty(true, false);
		return true;
	}

	bool GuiRemoteGraphicsParagraph::SetBackgroundColor(vint start, vint length, Color value)
	{
		CaretRange range;
		if (!TryBuildCaretRange(start, length, range)) return false;

		DocumentTextRunPropertyOverrides overrides;
		overrides.backgroundColor = value;
		AddTextRun(textRuns, range, overrides);
		MarkParagraphDirty(true, false);
		return true;
	}

	bool GuiRemoteGraphicsParagraph::SetInlineObject(vint start, vint length, const InlineObjectProperties& properties)
	{
		CaretRange range;
		if (!TryBuildCaretRange(start, length, range)) return false;

		vint backgroundElementId = -1;
		IGuiGraphicsRenderer* renderer = properties.backgroundImage ? properties.backgroundImage->GetRenderer() : nullptr;
		if (renderer)
		{
			renderer->SetRenderTarget(renderTarget);
			if (auto remoteRenderer = dynamic_cast<elements_remoteprotocol::IGuiRemoteProtocolElementRender*>(renderer))
			{
				backgroundElementId = remoteRenderer->GetID();
			}
		}

		remoteprotocol::DocumentInlineObjectRunProperty remoteProp;
		remoteProp.size = properties.size;
		remoteProp.baseline = properties.baseline;
		remoteProp.breakCondition = properties.breakCondition;
		remoteProp.backgroundColor = properties.backgroundColor;
		remoteProp.backgroundElementId = backgroundElementId;
		remoteProp.callbackId = properties.callbackId;

		if (!AddInlineObjectRun(inlineObjectRuns, range, remoteProp))
		{
			return false;
		}

		inlineObjectProperties.Remove(range);
		inlineObjectProperties.Add(range, properties);
		MarkParagraphDirty(true, true);
		return true;
	}

	bool GuiRemoteGraphicsParagraph::ResetInlineObject(vint start, vint length)
	{
		CaretRange range;
		if (!TryBuildCaretRange(start, length, range)) return false;
		if (!ResetInlineObjectRun(inlineObjectRuns, range)) return false;

		vint index = inlineObjectProperties.Keys().IndexOf(range);
		if (index != -1)
		{
			auto stored = inlineObjectProperties.Values()[index];
			if (stored.backgroundImage)
			{
				if (auto renderer = stored.backgroundImage->GetRenderer())
				{
					renderer->SetRenderTarget(nullptr);
				}
			}
			inlineObjectProperties.Remove(range);
		}

		MarkParagraphDirty(true, true);
		return true;
	}

	Size GuiRemoteGraphicsParagraph::GetSize()
	{
		EnsureRemoteParagraphSynced();
		return cachedSize;
	}

	bool GuiRemoteGraphicsParagraph::EnableCaret(vint caret, Color color, bool frontSide)
	{
		if (!EnsureRemoteParagraphSynced())
		{
			return false;
		}

		remoteprotocol::OpenCaretRequest request;
		request.id = id;
		request.caret = NativeTextPosToRemoteTextPos(caret);
		request.caretColor = color;
		request.frontSide = frontSide;

		auto& messages = renderTarget->GetRemoteMessages();
		messages.RequestDocumentParagraph_OpenCaret(request);
		bool disconnected = false;
		messages.Submit(disconnected);
		return !disconnected;
	}

	void GuiRemoteGraphicsParagraph::DisableCaret()
	{
		if (id == -1 || !renderTarget)
		{
			return;
		}

		auto& messages = renderTarget->GetRemoteMessages();
		messages.RequestDocumentParagraph_CloseCaret(id);
		bool disconnected = false;
		messages.Submit(disconnected);
	}

	bool GuiRemoteGraphicsParagraph::BlinkCaret()
	{
		return false;
	}

	void GuiRemoteGraphicsParagraph::Render(Rect bounds)
	{
		if (!renderTarget)
		{
			return;
		}

		if (!EnsureRemoteParagraphSynced())
		{
			return;
		}

		if (callback)
		{
			for (auto [callbackId, location] : cachedInlineObjectBounds)
			{
				auto newSize = callback->OnRenderInlineObject(callbackId, location);
				if (newSize != location.GetSize())
				{
					MarkParagraphDirty(false, true);
					for (auto&& inlineObjectRun : inlineObjectRuns.Values())
					{
						if (inlineObjectRun.callbackId == callbackId)
						{
							auto& editable = const_cast<remoteprotocol::DocumentInlineObjectRunProperty&>(inlineObjectRun);
							editable.size = newSize;
							break;
						}
					}
				}
			}
		}

		remoteprotocol::ElementRendering rendering;
		rendering.id = id;
		rendering.bounds = bounds;
		rendering.areaClippedByParent = renderTarget->GetClipperValidArea();

		auto& messages = renderTarget->GetRemoteMessages();
		messages.RequestRendererRenderElement(rendering);
		lastRenderedBatchId = renderTarget->renderingBatchId;
	}

	vint GuiRemoteGraphicsParagraph::GetCaret(vint comparingCaret, CaretRelativePosition position, bool& preferFrontSide)
	{
		if (!EnsureRemoteParagraphSynced())
		{
			preferFrontSide = false;
			return comparingCaret;
		}

		auto& messages = renderTarget->GetRemoteMessages();
		remoteprotocol::GetCaretRequest request;
		request.id = id;
		request.caret = NativeTextPosToRemoteTextPos(comparingCaret);
		request.relativePosition = position;

		vint requestId = messages.RequestDocumentParagraph_GetCaret(request);
		bool disconnected = false;
		messages.Submit(disconnected);
		if (disconnected)
		{
			preferFrontSide = false;
			return comparingCaret;
		}

		auto response = messages.RetrieveDocumentParagraph_GetCaret(requestId);
		preferFrontSide = response.preferFrontSide;
		return RemoteTextPosToNativeTextPos(response.newCaret);
	}

	bool GuiRemoteGraphicsParagraph::GetCaretBoundsInternal(vint caret, bool frontSide, Rect& bounds)
	{
		if (!cachedCaretBounds.frontSideBounds || !cachedCaretBounds.backSideBounds)
		{
			remoteprotocol::GetCaretBoundsRequest request;
			request.id = id;

			auto& messages = renderTarget->GetRemoteMessages();
			vint requestId = messages.RequestDocumentParagraph_GetCaretBounds(request);
			bool disconnected = false;
			messages.Submit(disconnected);
			if (disconnected)
			{
				return false;
			}

			cachedCaretBounds = messages.RetrieveDocumentParagraph_GetCaretBounds(requestId);
		}

		auto remoteCaret = NativeTextPosToRemoteTextPos(caret);
		if (frontSide)
		{
			bounds = cachedCaretBounds.frontSideBounds->Get(remoteCaret);
		}
		else
		{
			bounds = cachedCaretBounds.backSideBounds->Get(remoteCaret);
		}
		return true;
	}

	Rect GuiRemoteGraphicsParagraph::GetCaretBounds(vint caret, bool frontSide)
	{
		if (!EnsureRemoteParagraphSynced())
		{
			return {};
		}

		Rect bounds;
		GetCaretBoundsInternal(caret, frontSide, bounds);
		return bounds;
	}

	vint GuiRemoteGraphicsParagraph::GetCaretFromPoint(Point point)
	{
		if (!EnsureRemoteParagraphSynced())
		{
			return 0;
		}

		auto& messages = renderTarget->GetRemoteMessages();
		vint bestCaret = 0;
		vint bestDistance = -1;

		for (vint caret = 0; caret <= text.Length(); caret++)
		{
			Rect bounds;
			if (!GetCaretBoundsInternal(caret, true, bounds))
			{
				return bestCaret;
			}

			if (bounds.x1 <= point.x && point.x < bounds.x2 && bounds.y1 <= point.y && point.y < bounds.y2)
			{
				return caret;
			}

			vint horizontalDistance = 0;
			if (point.x < bounds.x1) horizontalDistance = bounds.x1 - point.x;
			else if (point.x > bounds.x2) horizontalDistance = point.x - bounds.x2;

			vint verticalDistance = 0;
			if (point.y < bounds.y1) verticalDistance = bounds.y1 - point.y;
			else if (point.y > bounds.y2) verticalDistance = point.y - bounds.y2;

			vint distance = horizontalDistance + verticalDistance;
			if (bestDistance == -1 || distance < bestDistance)
			{
				bestDistance = distance;
				bestCaret = caret;
			}
		}

		return bestCaret;
	}

	Nullable<IGuiGraphicsParagraph::InlineObjectProperties> GuiRemoteGraphicsParagraph::GetInlineObjectFromPoint(Point point, vint& start, vint& length)
	{
		start = 0;
		length = 0;

		if (!EnsureRemoteParagraphSynced())
		{
			return {};
		}

		remoteprotocol::GetInlineObjectFromPointRequest request;
		request.id = id;
		request.point = point;

		auto& messages = renderTarget->GetRemoteMessages();
		vint requestId = messages.RequestDocumentParagraph_GetInlineObjectFromPoint(request);
		bool disconnected = false;
		messages.Submit(disconnected);
		if (disconnected)
		{
			return {};
		}

		auto response = messages.RetrieveDocumentParagraph_GetInlineObjectFromPoint(requestId);
		if (!response)
		{
			return {};
		}

		CaretRange range;
		range.caretBegin = RemoteTextPosToNativeTextPos(response.Value().caretBegin);
		range.caretEnd = RemoteTextPosToNativeTextPos(response.Value().caretEnd);

		vint index = inlineObjectProperties.Keys().IndexOf(range);
		if (index == -1)
		{
			return {};
		}

		start = range.caretBegin;
		length = range.caretEnd - start;
		return inlineObjectProperties.Values()[index];
	}

	vint GuiRemoteGraphicsParagraph::GetNearestCaretFromTextPos(vint textPos, bool frontSide)
	{
		if (!EnsureRemoteParagraphSynced())
		{
			return textPos;
		}

		remoteprotocol::GetNearestCaretFromTextPosRequest request;
		request.id = id;
		request.textPos = NativeTextPosToRemoteTextPos(textPos);
		request.frontSide = frontSide;

		auto& messages = renderTarget->GetRemoteMessages();
		vint requestId = messages.RequestDocumentParagraph_GetNearestCaretFromTextPos(request);
		bool disconnected = false;
		messages.Submit(disconnected);
		if (disconnected)
		{
			return textPos;
		}

		auto response = messages.RetrieveDocumentParagraph_GetNearestCaretFromTextPos(requestId);
		return RemoteTextPosToNativeTextPos(response);
	}

	bool GuiRemoteGraphicsParagraph::IsValidCaret(vint caret)
	{
		if (!EnsureRemoteParagraphSynced())
		{
			return false;
		}

		remoteprotocol::IsValidCaretRequest request;
		request.id = id;
		request.caret = NativeTextPosToRemoteTextPos(caret);

		auto& messages = renderTarget->GetRemoteMessages();
		vint requestId = messages.RequestDocumentParagraph_IsValidCaret(request);
		bool disconnected = false;
		messages.Submit(disconnected);
		if (disconnected)
		{
			return false;
		}

		return messages.RetrieveDocumentParagraph_IsValidCaret(requestId);
	}

	bool GuiRemoteGraphicsParagraph::IsValidTextPos(vint textPos)
	{
		return 0 <= textPos && textPos <= text.Length();
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEGRAPHICS_DOCUMENT_HELPERS.CPP
***********************************************************************/

namespace vl::presentation::elements
{
	using namespace collections;

/***********************************************************************
Comparison
***********************************************************************/

	bool AreEqual(const DocumentTextRunPropertyOverrides& a, const DocumentTextRunPropertyOverrides& b)
	{
		return a.textColor == b.textColor &&
			   a.backgroundColor == b.backgroundColor &&
			   a.fontFamily == b.fontFamily &&
			   a.size == b.size &&
			   a.textStyle == b.textStyle;
	}

	bool AreEqual(const remoteprotocol::DocumentTextRunProperty& a, const remoteprotocol::DocumentTextRunProperty& b)
	{
		return a.textColor == b.textColor &&
			   a.backgroundColor == b.backgroundColor &&
			   a.fontProperties == b.fontProperties;
	}

	bool AreEqual(const remoteprotocol::DocumentRunProperty& a, const remoteprotocol::DocumentRunProperty& b)
	{
		if (a.Index() != b.Index())
			return false;

		if (auto textA = a.TryGet<remoteprotocol::DocumentTextRunProperty>())
		{
			auto textB = b.Get<remoteprotocol::DocumentTextRunProperty>();
			return AreEqual(*textA, textB);
		}
		else
		{
			auto inlineA = a.Get<remoteprotocol::DocumentInlineObjectRunProperty>();
			auto inlineB = b.Get<remoteprotocol::DocumentInlineObjectRunProperty>();
			return inlineA.size == inlineB.size &&
				inlineA.baseline == inlineB.baseline &&
				inlineA.breakCondition == inlineB.breakCondition &&
				inlineA.backgroundColor == inlineB.backgroundColor &&
				inlineA.backgroundElementId == inlineB.backgroundElementId &&
				inlineA.callbackId == inlineB.callbackId;
		}
	}

/***********************************************************************
AddTextRun
***********************************************************************/

	DocumentTextRunPropertyOverrides ApplyOverrides(
		const DocumentTextRunPropertyOverrides& base,
		const DocumentTextRunPropertyOverrides& overrides,
		bool& propertyOverrides)
	{
		if (overrides.textColor && base.textColor != overrides.textColor)					propertyOverrides = true;
		if (overrides.backgroundColor && base.backgroundColor != overrides.backgroundColor)	propertyOverrides = true;
		if (overrides.fontFamily && base.fontFamily != overrides.fontFamily)				propertyOverrides = true;
		if (overrides.size && base.size != overrides.size)									propertyOverrides = true;
		if (overrides.textStyle && base.textStyle != overrides.textStyle)					propertyOverrides = true;

		DocumentTextRunPropertyOverrides result;
		result.textColor = overrides.textColor ? overrides.textColor : base.textColor;
		result.backgroundColor = overrides.backgroundColor ? overrides.backgroundColor : base.backgroundColor;
		result.fontFamily = overrides.fontFamily ? overrides.fontFamily : base.fontFamily;
		result.size = overrides.size ? overrides.size : base.size;
		result.textStyle = overrides.textStyle ? overrides.textStyle : base.textStyle;
		return result;
	}

	bool AddTextRun(
		DocumentTextRunPropertyMap& map,
		CaretRange range,
		const DocumentTextRunPropertyOverrides& propertyOverrides)
	{
		vint firstOverlap = -1;
		bool semanticallyUpdated = false;
		
		if (map.Count() > 0)
		{
			auto comparer = [&](const CaretRange& key, const CaretRange& searchRange) -> std::strong_ordering
			{
				if (key.caretEnd <= searchRange.caretBegin)
					return std::strong_ordering::less;
				else if (key.caretBegin >= searchRange.caretEnd)
					return std::strong_ordering::greater;
				else
					return std::strong_ordering::equal;
			};

			vint index = -1;
			firstOverlap = BinarySearchLambda(&map.Keys()[0], map.Keys().Count(), range, index, comparer);
			
			// Binary search may return any overlapping entry, scan backwards to find the first one
			if (firstOverlap != -1)
			{
				while (firstOverlap > 0)
				{
					auto&& prevKey = map.Keys()[firstOverlap - 1];
					if (prevKey.caretEnd <= range.caretBegin || prevKey.caretBegin >= range.caretEnd)
						break;
					firstOverlap--;
				}
			}
		}
	
		List<Pair<CaretRange, DocumentTextRunPropertyOverrides>> fragmentsToReinsert;
		List<CaretRange> keysToRemove;
		List<Tuple<CaretRange, DocumentTextRunPropertyOverrides>> overlappingOldRuns;
		
		if (firstOverlap != -1)
		{
			auto&& keys = map.Keys();
			for (vint i = firstOverlap; i < keys.Count(); i++)
			{
				auto&& key = keys[i];
				if (key.caretBegin >= range.caretEnd)
					break;
			
				auto&& oldProperty = map[key];
			
				// Record the overlapping portion
				vint overlapBegin = key.caretBegin < range.caretBegin ? range.caretBegin : key.caretBegin;
				vint overlapEnd = key.caretEnd > range.caretEnd ? range.caretEnd : key.caretEnd;
				overlappingOldRuns.Add({CaretRange{overlapBegin, overlapEnd}, oldProperty});
			
				if (key.caretBegin < range.caretBegin)
				{
					CaretRange beforeRange{ key.caretBegin, range.caretBegin };
					fragmentsToReinsert.Add({ beforeRange, oldProperty });
				}
			
				if (key.caretEnd > range.caretEnd)
				{
					CaretRange afterRange{ range.caretEnd, key.caretEnd };
					fragmentsToReinsert.Add({ afterRange, oldProperty });
				}
			
				keysToRemove.Add(key);
			}
			
			for (auto&& key : keysToRemove)
			{
				map.Remove(key);
			}
		}
	
		for (auto&& fragment : fragmentsToReinsert)
		{
			map.Add(fragment.key, fragment.value);
		}
	
		if (overlappingOldRuns.Count() > 0)
		{
			// The new range has overlaps with old runs - apply override semantics
			vint currentPos = range.caretBegin;
			
			for (vint i = 0; i < overlappingOldRuns.Count(); i++)
			{
				auto&& [oldRange, oldProp] = overlappingOldRuns[i];
				
				// Add any gap before this overlap with new properties as-is
				if (currentPos < oldRange.caretBegin)
				{
					map.Add(CaretRange{currentPos, oldRange.caretBegin}, propertyOverrides);
					semanticallyUpdated = true;
				}
				
				// Add the overlapping portion with merged properties
				auto mergedProp = ApplyOverrides(oldProp, propertyOverrides, semanticallyUpdated);
				map.Add(oldRange, mergedProp);
				
				currentPos = oldRange.caretEnd;
			}
			
			// Add any remaining part after all overlaps with new properties as-is
			if (currentPos < range.caretEnd)
			{
				map.Add(CaretRange{currentPos, range.caretEnd}, propertyOverrides);
				semanticallyUpdated = true;
			}
		}
		else
		{
			// No overlaps - add the entire range with new properties
			map.Add(range, propertyOverrides);
			semanticallyUpdated = true;
		}

		// Find the first key within the original range for merging
		vint newIndex = -1;
		auto&& keys = map.Keys();
		for (vint i = 0; i < keys.Count(); i++)
		{
			if (keys[i].caretBegin >= range.caretBegin)
			{
				newIndex = i;
				break;
			}
		}
		
		if (newIndex != -1)
		{
			while (newIndex > 0)
			{
				CaretRange leftKey = map.Keys()[newIndex - 1];
				CaretRange currentKey = map.Keys()[newIndex];

				if (leftKey.caretEnd == currentKey.caretBegin &&
					AreEqual(map[leftKey], map[currentKey]))
				{
					CaretRange mergedRange{ leftKey.caretBegin, currentKey.caretEnd };
					auto mergedProperty = map[leftKey];

					map.Remove(leftKey);
					map.Remove(currentKey);
					map.Add(mergedRange, mergedProperty);

					newIndex = map.Keys().IndexOf(mergedRange);
				}
				else
				{
					break;
				}
			}

			while (newIndex < map.Keys().Count() - 1)
			{
				CaretRange currentKey = map.Keys()[newIndex];
				CaretRange rightKey = map.Keys()[newIndex + 1];

				if (currentKey.caretEnd == rightKey.caretBegin &&
					AreEqual(map[currentKey], map[rightKey]))
				{
					CaretRange mergedRange{ currentKey.caretBegin, rightKey.caretEnd };
					auto mergedProperty = map[currentKey];

					map.Remove(currentKey);
					map.Remove(rightKey);
					map.Add(mergedRange, mergedProperty);

					newIndex = map.Keys().IndexOf(mergedRange);
				}
				else
				{
					break;
				}
			}
		}
		return semanticallyUpdated;
	}

/***********************************************************************
AddInlineObjectRun
***********************************************************************/

	bool AddInlineObjectRun(
		DocumentInlineObjectRunPropertyMap& map,
		CaretRange range,
		const remoteprotocol::DocumentInlineObjectRunProperty& property)
	{
		if (map.Count() > 0)
		{
			auto comparer = [&](const CaretRange& key, const CaretRange& searchRange) -> std::strong_ordering
			{
				if (key.caretEnd <= searchRange.caretBegin)
					return std::strong_ordering::less;
				else if (key.caretBegin >= searchRange.caretEnd)
					return std::strong_ordering::greater;
				else
					return std::strong_ordering::equal;
			};

			vint index = -1;
			vint firstOverlap = BinarySearchLambda(&map.Keys()[0], map.Keys().Count(), range, index, comparer);
			
			if (firstOverlap != -1)
			{
				if (map.Keys()[firstOverlap] != range) return false;
				auto&& inlinedProps = const_cast<remoteprotocol::DocumentInlineObjectRunProperty&>(map.Values()[firstOverlap]);
				if (inlinedProps.callbackId != property.callbackId) return false;
				if (inlinedProps.backgroundElementId != property.backgroundElementId) return false;
				inlinedProps = property;
				return true;
			}
		}

		map.Add(range, property);
		return true;
	}

/***********************************************************************
ResetInlineObjectRun
***********************************************************************/

	bool ResetInlineObjectRun(
		DocumentInlineObjectRunPropertyMap& map,
		CaretRange range)
	{
		return map.Remove(range);
	}

/***********************************************************************
MergeRuns
***********************************************************************/

	remoteprotocol::DocumentTextRunProperty ConvertToFullProperty(const DocumentTextRunPropertyOverrides& propertyOverrides)
	{
		remoteprotocol::DocumentTextRunProperty fullProp;
		
		// Required properties - validate non-null
		CHECK_ERROR(propertyOverrides.fontFamily, L"fontFamily must be defined");
		CHECK_ERROR(propertyOverrides.size, L"size must be defined");
		
		fullProp.fontProperties.fontFamily = propertyOverrides.fontFamily.Value();
		fullProp.fontProperties.size = propertyOverrides.size.Value();
		
		// Optional properties - use defaults if null
		fullProp.textColor = propertyOverrides.textColor ? 
			propertyOverrides.textColor.Value() : Color(0, 0, 0);
		fullProp.backgroundColor = propertyOverrides.backgroundColor ? 
			propertyOverrides.backgroundColor.Value() : Color(0, 0, 0);
		
		auto style = propertyOverrides.textStyle ? 
			propertyOverrides.textStyle.Value() : (IGuiGraphicsParagraph::TextStyle)0;
		
		// Convert TextStyle enum flags to individual bool fields
		fullProp.fontProperties.bold = (style & IGuiGraphicsParagraph::TextStyle::Bold) != (IGuiGraphicsParagraph::TextStyle)0;
		fullProp.fontProperties.italic = (style & IGuiGraphicsParagraph::TextStyle::Italic) != (IGuiGraphicsParagraph::TextStyle)0;
		fullProp.fontProperties.underline = (style & IGuiGraphicsParagraph::TextStyle::Underline) != (IGuiGraphicsParagraph::TextStyle)0;
		fullProp.fontProperties.strikeline = (style & IGuiGraphicsParagraph::TextStyle::Strikeline) != (IGuiGraphicsParagraph::TextStyle)0;
		
		// Set default values for antialias properties
		fullProp.fontProperties.antialias = true;
		fullProp.fontProperties.verticalAntialias = true;
		
		return fullProp;
	}

	void MergeRuns(
		const DocumentTextRunPropertyMap& textRuns,
		const DocumentInlineObjectRunPropertyMap& inlineObjectRuns,
		DocumentRunPropertyMap& result)
	{
		result.Clear();

		vint textIdx = 0;
		vint inlineIdx = 0;

		auto&& textKeys = textRuns.Keys();
		auto&& inlineKeys = inlineObjectRuns.Keys();

		CaretRange currentTextRange;
		DocumentTextRunPropertyOverrides currentTextProperty;
		bool hasCurrentText = false;
		vint lastInlineEnd = -1;

		while (textIdx < textKeys.Count() || inlineIdx < inlineKeys.Count() || hasCurrentText)
		{
			if (!hasCurrentText && textIdx < textKeys.Count())
			{
				currentTextRange = textKeys[textIdx];
				currentTextProperty = textRuns[currentTextRange];
				hasCurrentText = true;
				textIdx++;
				
				// Trim text run if it overlaps with the last processed inline object
				if (lastInlineEnd > currentTextRange.caretBegin)
				{
					if (lastInlineEnd >= currentTextRange.caretEnd)
					{
						// Text run is completely within the last inline object
						hasCurrentText = false;
						continue;
					}
					else
					{
						// Text run partially overlaps, trim the beginning
						currentTextRange.caretBegin = lastInlineEnd;
					}
				}
			}

			if (hasCurrentText && inlineIdx >= inlineKeys.Count())
			{
				remoteprotocol::DocumentRunProperty runProp = ConvertToFullProperty(currentTextProperty);
				result.Add(currentTextRange, runProp);
				hasCurrentText = false;
				continue;
			}

			if (!hasCurrentText && inlineIdx < inlineKeys.Count())
			{
				auto&& inlineKey = inlineKeys[inlineIdx];
				remoteprotocol::DocumentRunProperty runProp = inlineObjectRuns[inlineKey];
				result.Add(inlineKey, runProp);
				lastInlineEnd = inlineKey.caretEnd;
				inlineIdx++;
				continue;
			}

			if (hasCurrentText && inlineIdx < inlineKeys.Count())
			{
				auto&& inlineKey = inlineKeys[inlineIdx];

				if (currentTextRange.caretEnd <= inlineKey.caretBegin)
				{
					remoteprotocol::DocumentRunProperty runProp = ConvertToFullProperty(currentTextProperty);
					result.Add(currentTextRange, runProp);
					hasCurrentText = false;
				}
				else if (inlineKey.caretEnd <= currentTextRange.caretBegin)
				{
					remoteprotocol::DocumentRunProperty runProp = inlineObjectRuns[inlineKey];
					result.Add(inlineKey, runProp);
					lastInlineEnd = inlineKey.caretEnd;
					inlineIdx++;
				}
				else
				{
					if (currentTextRange.caretBegin < inlineKey.caretBegin)
					{
						CaretRange beforeRange{ currentTextRange.caretBegin, inlineKey.caretBegin };
						
						remoteprotocol::DocumentRunProperty runProp = ConvertToFullProperty(currentTextProperty);
						result.Add(beforeRange, runProp);
					}

					remoteprotocol::DocumentRunProperty runProp = inlineObjectRuns[inlineKey];
					result.Add(inlineKey, runProp);
					lastInlineEnd = inlineKey.caretEnd;
					inlineIdx++;

					if (currentTextRange.caretEnd > inlineKey.caretEnd)
					{
						currentTextRange.caretBegin = inlineKey.caretEnd;
					}
					else
					{
						hasCurrentText = false;
					}
				}
			}
		}
	}

/***********************************************************************
DiffRuns
***********************************************************************/

	void DiffRuns(
		const DocumentRunPropertyMap& oldRuns,
		const DocumentRunPropertyMap& newRuns,
		remoteprotocol::ElementDesc_DocumentParagraph& result)
	{
		result.runsDiff = Ptr(new List<remoteprotocol::DocumentRun>());
		result.createdInlineObjects = Ptr(new List<vint>());
		result.removedInlineObjects = Ptr(new List<vint>());

		SortedList<vint> oldInlineCallbackIds;
		SortedList<vint> newInlineCallbackIds;

		vint oldIdx = 0;
		vint newIdx = 0;

		auto&& oldKeys = oldRuns.Keys();
		auto&& newKeys = newRuns.Keys();

		while (oldIdx < oldKeys.Count() || newIdx < newKeys.Count())
		{
			if (oldIdx >= oldKeys.Count())
			{
				auto&& newKey = newKeys[newIdx];
				auto&& newValue = newRuns[newKey];

				remoteprotocol::DocumentRun run;
				run.caretBegin = newKey.caretBegin;
				run.caretEnd = newKey.caretEnd;
				run.props = newValue;
				result.runsDiff->Add(run);

				if (auto inlineObj = newValue.TryGet<remoteprotocol::DocumentInlineObjectRunProperty>())
				{
					newInlineCallbackIds.Add(inlineObj->callbackId);
				}

				newIdx++;
				continue;
			}

			if (newIdx >= newKeys.Count())
			{
				auto&& oldKey = oldKeys[oldIdx];
				auto&& oldValue = oldRuns[oldKey];

				if (auto inlineObj = oldValue.TryGet<remoteprotocol::DocumentInlineObjectRunProperty>())
				{
					oldInlineCallbackIds.Add(inlineObj->callbackId);
				}

				oldIdx++;
				continue;
			}

			auto&& oldKey = oldKeys[oldIdx];
			auto&& newKey = newKeys[newIdx];

			if (oldKey == newKey)
			{
				auto&& oldValue = oldRuns[oldKey];
				auto&& newValue = newRuns[newKey];

				if (auto inlineObj = oldValue.TryGet<remoteprotocol::DocumentInlineObjectRunProperty>())
				{
					oldInlineCallbackIds.Add(inlineObj->callbackId);
				}
				if (auto inlineObj = newValue.TryGet<remoteprotocol::DocumentInlineObjectRunProperty>())
				{
					newInlineCallbackIds.Add(inlineObj->callbackId);
				}

				if (!AreEqual(oldValue, newValue))
				{
					remoteprotocol::DocumentRun run;
					run.caretBegin = newKey.caretBegin;
					run.caretEnd = newKey.caretEnd;
					run.props = newValue;
					result.runsDiff->Add(run);
				}

				oldIdx++;
				newIdx++;
			}
			else if (newKey < oldKey)
			{
				auto&& newValue = newRuns[newKey];

				remoteprotocol::DocumentRun run;
				run.caretBegin = newKey.caretBegin;
				run.caretEnd = newKey.caretEnd;
				run.props = newValue;
				result.runsDiff->Add(run);

				if (auto inlineObj = newValue.TryGet<remoteprotocol::DocumentInlineObjectRunProperty>())
				{
					newInlineCallbackIds.Add(inlineObj->callbackId);
				}

				newIdx++;
			}
			else
			{
				auto&& oldValue = oldRuns[oldKey];

				if (auto inlineObj = oldValue.TryGet<remoteprotocol::DocumentInlineObjectRunProperty>())
				{
					oldInlineCallbackIds.Add(inlineObj->callbackId);
				}

				oldIdx++;
			}
		}

#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::DiffRuns(const DocumentRunPropertyMap&, const DocumentRunPropertyMap&, remoteprotocol::ElementDesc_DocumentParagraph&)#"
		// Validate that all old run ranges are fully covered by new run ranges
		for (vint oldI = 0; oldI < oldKeys.Count(); oldI++)
		{
			auto&& oldKey = oldKeys[oldI];
			vint coveredEnd = oldKey.caretBegin;

			// Find all new ranges that cover this old range
			for (vint newI = 0; newI < newKeys.Count(); newI++)
			{
				auto&& newKey = newKeys[newI];

				// Check if this new range overlaps with uncovered part of old range
				if (newKey.caretBegin <= coveredEnd && newKey.caretEnd > coveredEnd)
				{
					coveredEnd = newKey.caretEnd > oldKey.caretEnd ? oldKey.caretEnd : newKey.caretEnd;
				}
			}

			CHECK_ERROR(coveredEnd >= oldKey.caretEnd,
				ERROR_MESSAGE_PREFIX L"Old run range not fully covered by new runs");
		}
#undef ERROR_MESSAGE_PREFIX

		for (vint i = 0; i < newInlineCallbackIds.Count(); i++)
		{
			auto id = newInlineCallbackIds[i];
			if (!oldInlineCallbackIds.Contains(id))
			{
				result.createdInlineObjects->Add(id);
			}
		}
		
		for (vint i = 0; i < oldInlineCallbackIds.Count(); i++)
		{
			auto id = oldInlineCallbackIds[i];
			if (!newInlineCallbackIds.Contains(id))
			{
				result.removedInlineObjects->Add(id);
			}
		}
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEGRAPHICS_IMAGESERVICE.CPP
***********************************************************************/

namespace vl::presentation
{
/***********************************************************************
GuiRemoteGraphicsImageFrame
***********************************************************************/

	GuiRemoteGraphicsImageFrame::GuiRemoteGraphicsImageFrame(GuiRemoteGraphicsImage* _image)
		: image(_image)
	{
	}

	GuiRemoteGraphicsImageFrame::~GuiRemoteGraphicsImageFrame()
	{
	}

	INativeImage* GuiRemoteGraphicsImageFrame::GetImage()
	{
		return image;
	}

	Size GuiRemoteGraphicsImageFrame::GetSize()
	{
		return size;
	}

/***********************************************************************
GuiRemoteGraphicsImage
***********************************************************************/

	void GuiRemoteGraphicsImage::EnsureMetadata()
	{
		if (status == MetadataStatus::Retrived) return;
		auto arguments = GenerateImageCreation();

		vint idImageCreated = remote->remoteMessages.RequestImageCreated(arguments);
		bool disconnected = false;
		remote->remoteMessages.Submit(disconnected);
		if (disconnected) return;
		auto imageMetadata = remote->remoteMessages.RetrieveImageCreated(idImageCreated);
		UpdateFromImageMetadata(imageMetadata);
	}

	GuiRemoteGraphicsImage::GuiRemoteGraphicsImage(GuiRemoteController* _remote, vint _id, Ptr<stream::MemoryStream> _binary)
		: remote(_remote)
		, id(_id)
		, binary(_binary)
	{
		remote->imageService.images.Add(id, this);
	}

	GuiRemoteGraphicsImage::~GuiRemoteGraphicsImage()
	{
		if (remote)
		{
			if (status == MetadataStatus::Retrived)
			{
				remote->remoteMessages.RequestImageDestroyed(id);
			}
			remote->imageService.images.Remove(id);
		}
	}

	stream::IStream& GuiRemoteGraphicsImage::GetBinaryData()
	{
		return *binary.Obj();
	}

	remoteprotocol::ImageCreation GuiRemoteGraphicsImage::GenerateImageCreation()
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::GuiRemoteGraphicsImage::GenerateImageCreation()#"
		CHECK_ERROR(status != MetadataStatus::Retrived, L"Cannot call this function when status is Retrived.");

		remoteprotocol::ImageCreation arguments;
		arguments.id = id;
		if (status == MetadataStatus::Uninitialized)
		{
			arguments.imageData = binary;
			arguments.imageDataOmitted = false;
			status = MetadataStatus::Requested;
		}
		else
		{
			arguments.imageDataOmitted = true;
		}

		return arguments;
#undef ERROR_MESSAGE_PREFIX
	}

	void GuiRemoteGraphicsImage::UpdateFromImageMetadata(const remoteprotocol::ImageMetadata& imageMetadata)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::GuiRemoteGraphicsImage::UpdateFromImageMetadata(const remoteprotocol::ImageMetadata&)#"

		CHECK_ERROR(id == imageMetadata.id, L"Wrong image metadata id specified.");

		format = imageMetadata.format;
		if (imageMetadata.frames)
		{
			if (frames.Count() > 0)
			{
				CHECK_ERROR(frames.Count() == imageMetadata.frames, L"New metadata should be identical to the last one.");
				for (auto [imageFrameMetadata, index] : indexed(*imageMetadata.frames.Obj()))
				{
					CHECK_ERROR(frames[index]->size == imageFrameMetadata.size, L"New metadata should be identical to the last one.");
				}
			}
			else
			{
				for (auto imageFrameMetadata : *imageMetadata.frames.Obj())
				{
					auto frame = Ptr(new GuiRemoteGraphicsImageFrame(this));
					frame->size = imageFrameMetadata.size;
					frames.Add(frame);
				}
			}
		}
		else
		{
			CHECK_ERROR(frames.Count() == 0, L"New metadata should be identical to the last one.");
		}

		status = MetadataStatus::Retrived;
#undef ERROR_MESSAGE_PREFIX
	}

	INativeImageService* GuiRemoteGraphicsImage::GetImageService()
	{
		return remote->ImageService();
	}

	INativeImage::FormatType GuiRemoteGraphicsImage::GetFormat()
	{
		EnsureMetadata();
		return format;
	}

	vint GuiRemoteGraphicsImage::GetFrameCount()
	{
		EnsureMetadata();
		return frames.Count();
	}

	INativeImageFrame* GuiRemoteGraphicsImage::GetFrame(vint index)
	{
		EnsureMetadata();
		return frames[index].Obj();
	}

	void GuiRemoteGraphicsImage::SaveToStream(stream::IStream& imageStream, FormatType formatType)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::GuiRemoteGraphicsImage::SaveToStream(IStream&, INativeImage::FormatType)#"
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"This function should not be called.");
#undef ERROR_MESSAGE_PREFIX
	}

/***********************************************************************
GuiRemoteGraphicsImageService
***********************************************************************/

	Ptr<GuiRemoteGraphicsImage> GuiRemoteGraphicsImageService::CreateImage(Ptr<stream::MemoryStream> binary)
	{
		return Ptr(new GuiRemoteGraphicsImage(remote, ++usedImageIds, binary));
	}

	GuiRemoteGraphicsImageService::GuiRemoteGraphicsImageService(GuiRemoteController* _remote)
		: remote(_remote)
	{
	}

	GuiRemoteGraphicsImageService::~GuiRemoteGraphicsImageService()
	{
	}

	void GuiRemoteGraphicsImageService::ResetImageMetadata()
	{
		for (auto image : images.Values())
		{
			image->status = GuiRemoteGraphicsImage::MetadataStatus::Uninitialized;
		}
	}

	void GuiRemoteGraphicsImageService::OnControllerConnect()
	{
		ResetImageMetadata();
	}

	void GuiRemoteGraphicsImageService::OnControllerDisconnect()
	{
	}

	void GuiRemoteGraphicsImageService::Initialize()
	{
	}

	void GuiRemoteGraphicsImageService::Finalize()
	{
		// TODO: (enumerable) foreach:reversed
		for (vint i = images.Count() - 1; i >= 0; i--)
		{
			images.Values()[i]->remote = nullptr;
		}
		images.Clear();
	}

	GuiRemoteGraphicsImage* GuiRemoteGraphicsImageService::GetImage(vint id)
	{
		return images[id];
	}

	Ptr<INativeImage> GuiRemoteGraphicsImageService::CreateImageFromFile(const WString& path)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::GuiRemoteGraphicsImageService::CreateImageFromFile(const WString&)#"
		CHECK_ERROR(remote, ERROR_MESSAGE_PREFIX L"This function cannot be called when GuiRemoteController is shut down.");
		stream::FileStream fileStream(path, stream::FileStream::ReadOnly);
		CHECK_ERROR(fileStream.IsAvailable(), ERROR_MESSAGE_PREFIX L"Unable to open file.");

		auto memoryStream = Ptr(new stream::MemoryStream((vint)fileStream.Size()));
		CopyStream(fileStream, *memoryStream.Obj());
		return CreateImage(memoryStream);
#undef ERROR_MESSAGE_PREFIX
	}

	Ptr<INativeImage> GuiRemoteGraphicsImageService::CreateImageFromMemory(void* buffer, vint length)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::GuiRemoteGraphicsImageService::CreateImageFromMemory(void*, vint)#"
		CHECK_ERROR(remote, ERROR_MESSAGE_PREFIX L"This function cannot be called when GuiRemoteController is shut down.");
		auto memoryStream = Ptr(new stream::MemoryStream(length));
		memoryStream->Write(buffer, length);
		return CreateImage(memoryStream);
#undef ERROR_MESSAGE_PREFIX
	}

	Ptr<INativeImage> GuiRemoteGraphicsImageService::CreateImageFromStream(stream::IStream& imageStream)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::GuiRemoteGraphicsImageService::CreateImageFromStream(IStream&)#"
		CHECK_ERROR(remote, ERROR_MESSAGE_PREFIX L"This function cannot be called when GuiRemoteController is shut down.");
		auto memoryStream = Ptr(new stream::MemoryStream(imageStream.IsLimited() ? (vint)imageStream.Size() : 65536));
		imageStream.SeekFromBegin(0);
		CopyStream(imageStream, *memoryStream.Obj());
		return CreateImage(memoryStream);
#undef ERROR_MESSAGE_PREFIX
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOLSCHEMASHARED.CPP
***********************************************************************/

namespace vl::presentation::remoteprotocol
{
	template<> Ptr<glr::json::JsonNode> ConvertCustomTypeToJson<bool>(const bool& value)
	{
		auto node = Ptr(new glr::json::JsonLiteral);
		node->value = value ? glr::json::JsonLiteralValue::True : glr::json::JsonLiteralValue::False;
		return node;
	}

	template<> Ptr<glr::json::JsonNode> ConvertCustomTypeToJson<vint>(const vint& value)
	{
		auto node = Ptr(new glr::json::JsonNumber);
		reflection::description::TypedValueSerializerProvider<vint>::Serialize(value, node->content.value);
		return node;
	}

	template<> Ptr<glr::json::JsonNode> ConvertCustomTypeToJson<float>(const float& value)
	{
		auto node = Ptr(new glr::json::JsonNumber);
		reflection::description::TypedValueSerializerProvider<float>::Serialize(value, node->content.value);
		return node;
	}

	template<> Ptr<glr::json::JsonNode> ConvertCustomTypeToJson<double>(const double& value)
	{
		auto node = Ptr(new glr::json::JsonNumber);
		reflection::description::TypedValueSerializerProvider<double>::Serialize(value, node->content.value);
		return node;
	}

	template<> Ptr<glr::json::JsonNode> ConvertCustomTypeToJson<WString>(const WString& value)
	{
		auto node = Ptr(new glr::json::JsonString);
		node->content.value = value;
		return node;
	}

	template<> Ptr<glr::json::JsonNode> ConvertCustomTypeToJson<wchar_t>(const wchar_t& value)
	{
		return ConvertCustomTypeToJson(WString::FromChar(value));
	}

	template<> Ptr<glr::json::JsonNode> ConvertCustomTypeToJson<VKEY>(const VKEY& value)
	{
		return ConvertCustomTypeToJson((vint)value);
	}

	template<> Ptr<glr::json::JsonNode> ConvertCustomTypeToJson<Color>(const Color& value)
	{
		return ConvertCustomTypeToJson(value.ToString());
	}

	template<> Ptr<glr::json::JsonNode> ConvertCustomTypeToJson<Ptr<stream::MemoryStream>>(const Ptr<stream::MemoryStream>& value)
	{
		if (!value)
		{
			auto node = Ptr(new glr::json::JsonLiteral);
			node->value = glr::json::JsonLiteralValue::Null;
			return node;
		}

		stream::MemoryStream base64WStringStream;
		{
			stream::UtfGeneralEncoder<wchar_t, char8_t> utf8ToWCharEncoder;
			stream::EncoderStream utf8ToWCharStream(base64WStringStream, utf8ToWCharEncoder);
			stream::Utf8Base64Encoder binaryToBase64Utf8Encoder;
			stream::EncoderStream binaryToBase64Utf8Stream(utf8ToWCharStream, binaryToBase64Utf8Encoder);
			value->SeekFromBegin(0);
			stream::CopyStream(*value.Obj(), binaryToBase64Utf8Stream);
		}
		{
			base64WStringStream.SeekFromBegin(0);
			stream::StreamReader reader(base64WStringStream);
			return ConvertCustomTypeToJson(reader.ReadToEnd());
		}
	}

	template<> void ConvertJsonToCustomType<bool>(Ptr<glr::json::JsonNode> node, bool& value)
	{
#define ERROR_MESSAGE_PREFIX L"presentation::remoteprotocol::ConvertJsonToCustomType<bool>(Ptr<JsonNode>, bool&)#"
		auto jsonNode = node.Cast<glr::json::JsonLiteral>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"JSON node does not match the expected type.");
		switch (jsonNode->value)
		{
		case glr::json::JsonLiteralValue::True: value = true; break;
		case glr::json::JsonLiteralValue::False: value = false; break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported json literal.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<vint>(Ptr<glr::json::JsonNode> node, vint& value)
	{
#define ERROR_MESSAGE_PREFIX L"presentation::remoteprotocol::ConvertJsonToCustomType<vint>(Ptr<JsonNode>, vint&)#"
		auto jsonNode = node.Cast<glr::json::JsonNumber>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"JSON node does not match the expected type.");
		CHECK_ERROR(reflection::description::TypedValueSerializerProvider<vint>::Deserialize(jsonNode->content.value, value), ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<float>(Ptr<glr::json::JsonNode> node, float& value)
	{
#define ERROR_MESSAGE_PREFIX L"presentation::remoteprotocol::ConvertJsonToCustomType<float>(Ptr<JsonNode>, float&)#"
		auto jsonNode = node.Cast<glr::json::JsonNumber>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"JSON node does not match the expected type.");
		CHECK_ERROR(reflection::description::TypedValueSerializerProvider<float>::Deserialize(jsonNode->content.value, value), ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<double>(Ptr<glr::json::JsonNode> node, double& value)
	{
#define ERROR_MESSAGE_PREFIX L"presentation::remoteprotocol::ConvertJsonToCustomType<double>(Ptr<JsonNode>, double&)#"
		auto jsonNode = node.Cast<glr::json::JsonNumber>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"JSON node does not match the expected type.");
		CHECK_ERROR(reflection::description::TypedValueSerializerProvider<double>::Deserialize(jsonNode->content.value, value), ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<WString>(Ptr<glr::json::JsonNode> node, WString& value)
	{
#define ERROR_MESSAGE_PREFIX L"presentation::remoteprotocol::ConvertJsonToCustomType<WString>(Ptr<JsonNode>, WString&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"JSON node does not match the expected type.");
		value = jsonNode->content.value;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<wchar_t>(Ptr<glr::json::JsonNode> node, wchar_t& value)
	{
#define ERROR_MESSAGE_PREFIX L"presentation::remoteprotocol::ConvertJsonToCustomType<wchar_t>(Ptr<JsonNode>, wchar_t&)#"
		WString strValue;
		ConvertJsonToCustomType(node, strValue);
		CHECK_ERROR(strValue.Length() == 1, ERROR_MESSAGE_PREFIX L"Char in JSON should be a string with one char.");
		value = strValue[0];
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<VKEY>(Ptr<glr::json::JsonNode> node, VKEY& value)
	{
		vint intValue;
		ConvertJsonToCustomType(node, intValue);
		value = (VKEY)intValue;
	}

	template<> void ConvertJsonToCustomType<Color>(Ptr<glr::json::JsonNode> node, Color& value)
	{
		WString strValue;
		ConvertJsonToCustomType(node, strValue);
		value = Color::Parse(strValue);
	}

	template<> void ConvertJsonToCustomType<Ptr<stream::MemoryStream>>(Ptr<glr::json::JsonNode> node, Ptr<stream::MemoryStream>& value)
	{
		if (auto jsonLiteral = node.Cast<glr::json::JsonLiteral>())
		{
			if (jsonLiteral->value == glr::json::JsonLiteralValue::Null)
			{
				value = {};
				return;
			}
		}
		else
		{
			WString base64;
			ConvertJsonToCustomType(node, base64);

			value = Ptr(new stream::MemoryStream);

			stream::MemoryWrapperStream base64WStringStream((void*)base64.Buffer(), base64.Length() * sizeof(wchar_t));
			stream::UtfGeneralDecoder<wchar_t, char8_t> wcharToUtf8Decoder;
			stream::DecoderStream wcharToUtf8Stream(base64WStringStream, wcharToUtf8Decoder);
			stream::Utf8Base64Decoder base64Utf8ToBinaryDecoder;
			stream::DecoderStream base64Utf8ToBinaryStream(wcharToUtf8Stream, base64Utf8ToBinaryDecoder);

			stream::CopyStream(base64Utf8ToBinaryStream, *value.Obj());
		}
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_CHANNEL_ASYNC.CPP
***********************************************************************/

namespace vl::presentation::remoteprotocol::channeling
{
	using namespace vl::collections;
	using namespace vl::presentation::controls;

/***********************************************************************
GuiRemoteProtocolAsyncJsonChannel
***********************************************************************/

	bool GuiRemoteProtocolAsyncJsonChannel::AreCurrentPendingRequestGroupSatisfied(bool disconnected)
	{
		if (!pendingRequest) return false;
		if (disconnected) return true;
		for (vint requestId : pendingRequest->requestIds)
		{
			if (!queuedResponses.Keys().Contains(requestId))
			{
				return false;
			}
		}
		return true;
	}

	void GuiRemoteProtocolAsyncJsonChannel::ScheduleProcessRemoteEvents()
	{
		auto app = GetApplication();
		if (!app)
		{
			return;
		}

		bool shouldQueue = false;
		SPIN_LOCK(lockEvents)
		{
			if (!uiTaskQueued)
			{
				uiTaskQueued = true;
				shouldQueue = true;
			}
		}

		if (shouldQueue)
		{
			app->InvokeInMainThread(app->GetMainWindow(), [this]()
			{
				ProcessChannelEvents();
			});
		}
	}

	void GuiRemoteProtocolAsyncJsonChannel::ProcessChannelEvents()
	{
		List<ReceivedPackage> events;
		SPIN_LOCK(lockEvents)
		{
			events = std::move(queuedEvents);
			uiTaskQueued = false;
		}

		auto processEvent = [this](const ReceivedPackage& eventPackage)
		{
			reader->OnRead(eventPackage.senderClientId, eventPackage.package);
		};

		for (auto&& eventPackage : events)
		{
			ChannelPackageInfo info;
			Ptr<glr::json::JsonNode> jsonArguments;
			JsonChannelUnpack(eventPackage.package, info, jsonArguments);

			vint currentConnectionClientId = -1;
			SPIN_LOCK(lockConnection)
			{
				currentConnectionClientId = connectionClientId;
			}

			if (info.name == L"ControllerConnect" && eventPackage.senderClientId == currentConnectionClientId)
			{
				processEvent(eventPackage);
			}
		}

		for (auto&& eventPackage : events)
		{
			ChannelPackageInfo info;
			Ptr<glr::json::JsonNode> jsonArguments;
			JsonChannelUnpack(eventPackage.package, info, jsonArguments);

			vint currentConnectionClientId = -1;
			SPIN_LOCK(lockConnection)
			{
				currentConnectionClientId = connectionClientId;
			}

			if (info.name != L"ControllerConnect" && eventPackage.senderClientId == currentConnectionClientId)
			{
				processEvent(eventPackage);
			}
		}
	}

	void GuiRemoteProtocolAsyncJsonChannel::ProcessRemoteEvents()
	{
		if (remoteEventProcessor)
		{
			remoteEventProcessor->ProcessRemoteEvents();
		}
		ProcessChannelEvents();
	}

	void GuiRemoteProtocolAsyncJsonChannel::OnRead(vint senderClientId, const JsonPackage& package)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolAsyncJsonChannel::OnRead(vint, const JsonPackage&)#"
		ChannelPackageInfo info;
		Ptr<glr::json::JsonNode> jsonArguments;
		JsonChannelUnpack(package, info, jsonArguments);

		switch (info.semantic)
		{
		case ChannelPackageSemantic::Event:
			{
				if (info.name == L"ControllerConnect")
				{
					SPIN_LOCK(lockConnection)
					{
						connectionCounter++;
						connectionClientId = senderClientId;
						connectionAvailable = true;
					}

					SPIN_LOCK(lockResponses)
					{
						if (pendingRequest)
						{
							eventAutoResponses.Signal();
						}
					}
				}

				ReceivedPackage receivedPackage;
				receivedPackage.senderClientId = senderClientId;
				receivedPackage.package = package;
				SPIN_LOCK(lockEvents)
				{
					queuedEvents.Add(receivedPackage);
				}
				ScheduleProcessRemoteEvents();
			}
			break;
		case ChannelPackageSemantic::Response:
			{
				ReceivedPackage receivedPackage;
				receivedPackage.senderClientId = senderClientId;
				receivedPackage.package = package;
				SPIN_LOCK(lockResponses)
				{
					queuedResponses.Add(info.id, receivedPackage);
					if (AreCurrentPendingRequestGroupSatisfied(false))
					{
						eventAutoResponses.Signal();
					}
				}
			}
			break;
		default:
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Only responses and events are expected.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	GuiRemoteProtocolAsyncJsonChannel::GuiRemoteProtocolAsyncJsonChannel(IJsonChannel* _channel, IGuiRemoteEventProcessor* _remoteEventProcessor)
		: channel(_channel)
		, remoteEventProcessor(_remoteEventProcessor)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolAsyncJsonChannel::GuiRemoteProtocolAsyncJsonChannel(IJsonChannel*, IGuiRemoteEventProcessor*)#"
		CHECK_ERROR(channel, ERROR_MESSAGE_PREFIX L"A valid channel is required.");
		CHECK_ERROR(eventAutoResponses.CreateAutoUnsignal(false), ERROR_MESSAGE_PREFIX L"Failed to initialize eventAutoResponses.");
#undef ERROR_MESSAGE_PREFIX
	}

	GuiRemoteProtocolAsyncJsonChannel::~GuiRemoteProtocolAsyncJsonChannel()
	{
	}

	const WString& GuiRemoteProtocolAsyncJsonChannel::GetChannelName()
	{
		return channel->GetChannelName();
	}

	IJsonChannelReader* GuiRemoteProtocolAsyncJsonChannel::GetReader()
	{
		return reader;
	}

	void GuiRemoteProtocolAsyncJsonChannel::Initialize(IJsonChannelReader* _reader)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolAsyncJsonChannel::Initialize(IJsonChannelReader*)#"
		CHECK_ERROR(_reader, ERROR_MESSAGE_PREFIX L"A valid reader is required.");
		CHECK_ERROR(!reader, ERROR_MESSAGE_PREFIX L"The async channel cannot be initialized more than once.");
		reader = _reader;
		channel->Initialize(this);
#undef ERROR_MESSAGE_PREFIX
	}

	void GuiRemoteProtocolAsyncJsonChannel::SendToClient(vint receiverClientId, const JsonPackage& package)
	{
		QueuedPackage queuedPackage;
		queuedPackage.receiverClientId = receiverClientId;
		queuedPackage.package = package;

		SPIN_LOCK(lockPendingPackages)
		{
			pendingPackages.Add(queuedPackage);
		}
	}

	void GuiRemoteProtocolAsyncJsonChannel::BroadcastFromClient(const JsonPackage& package)
	{
		List<vint> blockedReceivers;
		BroadcastFromClient(package, blockedReceivers);
	}

	void GuiRemoteProtocolAsyncJsonChannel::BroadcastFromClient(const JsonPackage& package, const List<vint>& blockedReceivers)
	{
		QueuedPackage queuedPackage;
		queuedPackage.package = package;
		queuedPackage.blockedReceivers = Ptr(new List<vint>);
		CopyFrom(*queuedPackage.blockedReceivers.Obj(), blockedReceivers);

		SPIN_LOCK(lockPendingPackages)
		{
			pendingPackages.Add(queuedPackage);
		}
	}

	void GuiRemoteProtocolAsyncJsonChannel::BatchWrite(bool& disconnected)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolAsyncJsonChannel::BatchWrite(bool&)#"
		disconnected = false;

		List<QueuedPackage> packages;
		SPIN_LOCK(lockPendingPackages)
		{
			packages = std::move(pendingPackages);
		}

		if (packages.Count() == 0)
		{
			return;
		}

		vint currentConnectionCounter = -1;
		SPIN_LOCK(lockConnection)
		{
			currentConnectionCounter = connectionCounter;
			if (!connectionAvailable)
			{
				disconnected = true;
				return;
			}
		}

		auto requestGroup = Ptr(new PendingRequestGroup);
		requestGroup->connectionCounter = currentConnectionCounter;
		for (auto&& queuedPackage : packages)
		{
			ChannelPackageInfo info;
			Ptr<glr::json::JsonNode> jsonArguments;
			JsonChannelUnpack(queuedPackage.package, info, jsonArguments);

			if (info.semantic == ChannelPackageSemantic::Request)
			{
				requestGroup->requestIds.Add(info.id);
			}
		}

		SPIN_LOCK(lockResponses)
		{
			CHECK_ERROR(!pendingRequest, ERROR_MESSAGE_PREFIX L"Only one pending request group is expected.");
			pendingRequest = requestGroup;
		}

		for (auto&& queuedPackage : packages)
		{
			if (queuedPackage.receiverClientId)
			{
				channel->SendToClient(queuedPackage.receiverClientId.Value(), queuedPackage.package);
			}
			else
			{
				if (queuedPackage.blockedReceivers)
				{
					channel->BroadcastFromClient(queuedPackage.package, *queuedPackage.blockedReceivers.Obj());
				}
				else
				{
					channel->BroadcastFromClient(queuedPackage.package);
				}
			}
		}
		channel->BatchWrite(disconnected);

		if (disconnected || requestGroup->requestIds.Count() == 0)
		{
			eventAutoResponses.Signal();
		}

		eventAutoResponses.Wait();
		SPIN_LOCK(lockConnection)
		{
			if (requestGroup->connectionCounter != connectionCounter || !connectionAvailable)
			{
				disconnected = true;
			}
		}

		List<ReceivedPackage> responses;
		SPIN_LOCK(lockResponses)
		{
			if (!disconnected)
			{
				for (vint id : requestGroup->requestIds)
				{
					responses.Add(queuedResponses[id]);
					queuedResponses.Remove(id);
				}
			}
			pendingRequest = nullptr;
			queuedResponses.Clear();
		}

		for (auto&& response : responses)
		{
			reader->OnRead(response.senderClientId, response.package);
		}
#undef ERROR_MESSAGE_PREFIX
	}

	IGuiRemoteEventProcessor* GuiRemoteProtocolAsyncJsonChannel::GetRemoteEventProcessor()
	{
		return this;
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_CHANNEL_ASYNCRENDERER.CPP
***********************************************************************/

namespace vl::presentation::remoteprotocol::channeling
{
	using namespace vl::collections;

/***********************************************************************
GuiRemoteProtocolAsyncJsonChannelRenderer
***********************************************************************/

	void GuiRemoteProtocolAsyncJsonChannelRenderer::ScheduleProcessRemoteMessages()
	{
		IGuiRemoteProtocolAsyncRendererInvoker* invoker = nullptr;
		SPIN_LOCK(lockMessages)
		{
			if (invokeInMainThread && !uiTaskQueued && queuedMessages.Count() > 0)
			{
				uiTaskQueued = true;
				invoker = invokeInMainThread;
			}
		}

		if (invoker)
		{
			invoker->InvokeInMainThread([this]()
			{
				ProcessRemoteMessages();
			});
		}
	}

	void GuiRemoteProtocolAsyncJsonChannelRenderer::ProcessRemoteMessages()
	{
		while (true)
		{
			IJsonChannelReader* currentReader = nullptr;
			vint currentMessageVersion = -1;
			List<ReceivedPackage> messages;
			SPIN_LOCK(lockMessages)
			{
				currentReader = reader;
				currentMessageVersion = messageVersion;
				if (!currentReader)
				{
					queuedMessages.Clear();
					uiTaskQueued = false;
					return;
				}

				messages = std::move(queuedMessages);
				if (messages.Count() == 0)
				{
					uiTaskQueued = false;
					return;
				}
			}

			for (auto&& message : messages)
			{
				bool shouldProcess = false;
				SPIN_LOCK(lockMessages)
				{
					shouldProcess = reader == currentReader && message.messageVersion == currentMessageVersion;
				}

				if (shouldProcess)
				{
					currentReader->OnRead(message.senderClientId, message.package);
				}
			}
		}
	}

	void GuiRemoteProtocolAsyncJsonChannelRenderer::OnRead(vint senderClientId, const JsonPackage& package)
	{
		ReceivedPackage receivedPackage;
		receivedPackage.senderClientId = senderClientId;
		receivedPackage.package = package;
		SPIN_LOCK(lockMessages)
		{
			if (!reader)
			{
				return;
			}
			receivedPackage.messageVersion = messageVersion;
			queuedMessages.Add(std::move(receivedPackage));
		}
		ScheduleProcessRemoteMessages();
	}

	GuiRemoteProtocolAsyncJsonChannelRenderer::GuiRemoteProtocolAsyncJsonChannelRenderer(IJsonChannel* _channel)
		: channel(_channel)
	{
	}

	GuiRemoteProtocolAsyncJsonChannelRenderer::~GuiRemoteProtocolAsyncJsonChannelRenderer()
	{
		SPIN_LOCK(lockMessages)
		{
			invokeInMainThread = nullptr;
			queuedMessages.Clear();
			uiTaskQueued = false;
		}
	}

	const WString& GuiRemoteProtocolAsyncJsonChannelRenderer::GetChannelName()
	{
		return channel->GetChannelName();
	}

	IJsonChannelReader* GuiRemoteProtocolAsyncJsonChannelRenderer::GetReader()
	{
		return reader;
	}

	void GuiRemoteProtocolAsyncJsonChannelRenderer::Initialize(IJsonChannelReader* _reader)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolAsyncJsonChannelRenderer::Initialize(IJsonChannelReader*)#"
		CHECK_ERROR(_reader, ERROR_MESSAGE_PREFIX L"The reader must not be null. Call Detach() to clear the reader.");
		bool initializeChannel = false;
		SPIN_LOCK(lockMessages)
		{
			reader = _reader;
			if (reader && !channelInitialized)
			{
				channelInitialized = true;
				initializeChannel = true;
			}
		}
		if (initializeChannel)
		{
			channel->Initialize(this);
		}
#undef ERROR_MESSAGE_PREFIX
	}

	void GuiRemoteProtocolAsyncJsonChannelRenderer::SendToClient(vint receiverClientId, const JsonPackage& package)
	{
		channel->SendToClient(receiverClientId, package);
	}

	void GuiRemoteProtocolAsyncJsonChannelRenderer::BroadcastFromClient(const JsonPackage& package)
	{
		channel->BroadcastFromClient(package);
	}

	void GuiRemoteProtocolAsyncJsonChannelRenderer::BroadcastFromClient(const JsonPackage& package, const List<vint>& blockedReceivers)
	{
		channel->BroadcastFromClient(package, blockedReceivers);
	}

	void GuiRemoteProtocolAsyncJsonChannelRenderer::BatchWrite(bool& disconnected)
	{
		channel->BatchWrite(disconnected);
	}

	void GuiRemoteProtocolAsyncJsonChannelRenderer::SetInvokeInMainThread(IGuiRemoteProtocolAsyncRendererInvoker* _invokeInMainThread)
	{
		SPIN_LOCK(lockMessages)
		{
			invokeInMainThread = _invokeInMainThread;
		}
		ScheduleProcessRemoteMessages();
	}

	void GuiRemoteProtocolAsyncJsonChannelRenderer::Detach()
	{
		SPIN_LOCK(lockMessages)
		{
			reader = nullptr;
			messageVersion++;
			queuedMessages.Clear();
			uiTaskQueued = false;
		}
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_CHANNEL_JSON.CPP
***********************************************************************/

namespace vl::presentation::remoteprotocol::channeling
{
	using namespace vl::collections;

/***********************************************************************
ChannelPackageSemantic
***********************************************************************/

	void JsonChannelPack(const ChannelPackageInfo& info, Ptr<glr::json::JsonNode> arguments, Ptr<glr::json::JsonObject>& package)
	{
		package = Ptr(new glr::json::JsonObject);

		{
			auto value = Ptr(new glr::json::JsonString);
			switch (info.semantic)
			{
			case ChannelPackageSemantic::Message:
				value->content.value = WString::Unmanaged(L"Message");
				break;
			case ChannelPackageSemantic::Request:
				value->content.value = WString::Unmanaged(L"Request");
				break;
			case ChannelPackageSemantic::Response:
				value->content.value = WString::Unmanaged(L"Response");
				break;
			case ChannelPackageSemantic::Event:
				value->content.value = WString::Unmanaged(L"Event");
				break;
			default:
				value->content.value = WString::Unmanaged(L"Unknown");
			}

			auto field = Ptr(new glr::json::JsonObjectField);
			field->name.value = WString::Unmanaged(L"semantic");
			field->value = value;
			package->fields.Add(field);
		}

		if (info.id != -1)
		{
			auto value = Ptr(new glr::json::JsonNumber);
			value->content.value = itow(info.id);

			auto field = Ptr(new glr::json::JsonObjectField);
			field->name.value = WString::Unmanaged(L"id");
			field->value = value;
			package->fields.Add(field);
		}

		{
			auto value = Ptr(new glr::json::JsonString);
			value->content.value = info.name;

			auto field = Ptr(new glr::json::JsonObjectField);
			field->name.value = WString::Unmanaged(L"name");
			field->value = value;
			package->fields.Add(field);
		}

		if (arguments)
		{
			auto field = Ptr(new glr::json::JsonObjectField);
			field->name.value = WString::Unmanaged(L"arguments");
			field->value = arguments;
			package->fields.Add(field);
		}
	}

	void JsonChannelUnpack(Ptr<glr::json::JsonObject> package, ChannelPackageInfo& info, Ptr<glr::json::JsonNode>& arguments)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::JsonChannelUnpack(Ptr<JsonObject>, ChannelPackageInfo&, Ptr<JsonNode>&)#"
		CHECK_ERROR(package, ERROR_MESSAGE_PREFIX L"The package should be a JsonObject.");

		info = {};
		arguments = {};

		for (auto&& field : package->fields)
		{
			if (field->name.value == L"semantic")
			{
				auto value = field->value.Cast<glr::json::JsonString>();
				CHECK_ERROR(value, ERROR_MESSAGE_PREFIX L"The semantic field should be a string.");

				if (value->content.value == L"Message")
				{
					info.semantic = ChannelPackageSemantic::Message;
				}
				else if (value->content.value == L"Request")
				{
					info.semantic = ChannelPackageSemantic::Request;
				}
				else if (value->content.value == L"Response")
				{
					info.semantic = ChannelPackageSemantic::Response;
				}
				else if (value->content.value == L"Event")
				{
					info.semantic = ChannelPackageSemantic::Event;
				}
			}
			else if (field->name.value == L"id")
			{
				auto value = field->value.Cast<glr::json::JsonNumber>();
				CHECK_ERROR(value, ERROR_MESSAGE_PREFIX L"The id field should be a number.");

				info.id = wtoi(value->content.value);
			}
			else if (field->name.value == L"name")
			{
				auto value = field->value.Cast<glr::json::JsonString>();
				CHECK_ERROR(value, ERROR_MESSAGE_PREFIX L"The name field should be a string.");

				info.name = value->content.value;
			}
			else if (field->name.value == L"arguments")
			{
				arguments = field->value;
			}
		}

		CHECK_ERROR(info.semantic != ChannelPackageSemantic::Unknown, ERROR_MESSAGE_PREFIX L"The semantic field is missing or invalid.");
		CHECK_ERROR(info.name.Length() > 0, ERROR_MESSAGE_PREFIX L"The name field is missing.");
#undef ERROR_MESSAGE_PREFIX
	}

	void JsonChannelUnpack(Ptr<glr::json::JsonNode> package, ChannelPackageInfo& info, Ptr<glr::json::JsonNode>& arguments)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::JsonChannelUnpack(Ptr<JsonNode>, ChannelPackageInfo&, Ptr<JsonNode>&)#"
		auto object = package.Cast<glr::json::JsonObject>();
		CHECK_ERROR(object, ERROR_MESSAGE_PREFIX L"The package should be a JsonObject.");
		JsonChannelUnpack(object, info, arguments);
#undef ERROR_MESSAGE_PREFIX
	}

/***********************************************************************
GuiRemoteProtocolChannelClient
***********************************************************************/

	GuiRemoteProtocolChannelClient::GuiRemoteProtocolChannelClient(Ptr<inter_process::INetworkProtocolClient> client, Ptr<glr::json::Parser> parser)
		: Base(client, parser)
	{
		channelNames.Add(WString::Unmanaged(GacUIRemoteProtocolChannelName), nullptr);
	}

	const IJsonChannelClient::ChannelNameList& GuiRemoteProtocolChannelClient::OnGetChannelNames()
	{
		return channelNames.Keys();
	}

	IJsonChannel* GuiRemoteProtocolChannelClient::GetProtocolChannel()
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolChannelClient::GetProtocolChannel()#"
		auto&& channels = GetChannels();
		auto index = channels.Keys().IndexOf(WString::Unmanaged(GacUIRemoteProtocolChannelName));
		CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"The protocol channel is missing.");
		return channels.Values()[index];
#undef ERROR_MESSAGE_PREFIX
	}

/***********************************************************************
GuiRemoteProtocolLocalChannelClient
***********************************************************************/

	GuiRemoteProtocolLocalChannelClient::GuiRemoteProtocolLocalChannelClient(Ptr<glr::json::Parser> parser)
		: Base(parser)
	{
		channelNames.Add(WString::Unmanaged(GacUIRemoteProtocolChannelName), nullptr);
	}

	const IJsonChannelClient::ChannelNameList& GuiRemoteProtocolLocalChannelClient::OnGetChannelNames()
	{
		return channelNames.Keys();
	}

	IJsonChannel* GuiRemoteProtocolLocalChannelClient::GetProtocolChannel()
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolLocalChannelClient::GetProtocolChannel()#"
		auto&& channels = GetChannels();
		auto index = channels.Keys().IndexOf(WString::Unmanaged(GacUIRemoteProtocolChannelName));
		CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"The protocol channel is missing.");
		return channels.Values()[index];
#undef ERROR_MESSAGE_PREFIX
	}

/***********************************************************************
GuiRemoteProtocolCoreChannel
***********************************************************************/

#define EVENT_NOREQ(NAME, REQUEST)\
	void GuiRemoteProtocolCoreChannel::OnRead_Event_ ## NAME (Ptr<glr::json::JsonNode> jsonArguments)\
	{\
		events->On ## NAME();\
	}\

#define EVENT_REQ(NAME, REQUEST)\
	void GuiRemoteProtocolCoreChannel::OnRead_Event_ ## NAME (Ptr<glr::json::JsonNode> jsonArguments)\
	{\
		REQUEST arguments;\
		ConvertJsonToCustomType(jsonArguments, arguments);\
		events->On ## NAME(arguments);\
	}\

#define EVENT_HANDLER(NAME, REQUEST, REQTAG, ...)	EVENT_ ## REQTAG(NAME, REQUEST)
	GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER)
#undef EVENT_HANDLER
#undef EVENT_REQ
#undef EVENT_NOREQ

#define MESSAGE_NORES(NAME, RESPONSE)

#define MESSAGE_RES(NAME, RESPONSE)\
	void GuiRemoteProtocolCoreChannel::OnRead_Response_ ## NAME (vint id, Ptr<glr::json::JsonNode> jsonArguments)\
	{\
		RESPONSE arguments;\
		ConvertJsonToCustomType(jsonArguments, arguments);\
		events->Respond ## NAME(id, arguments);\
	}\

#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## RESTAG(NAME, RESPONSE)
	GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_RES
#undef MESSAGE_NORES

	void GuiRemoteProtocolCoreChannel::Write(Ptr<glr::json::JsonObject> package)
	{
		auto receiverClientId = GetRendererClientId();
		if (receiverClientId == -1)
		{
			SPIN_LOCK(lockPackagesBeforeRenderer)
			{
				packagesBeforeRenderer.Add(package);
			}
		}
		else
		{
			List<JsonPackage> packages;
			SPIN_LOCK(lockPackagesBeforeRenderer)
			{
				packages = std::move(packagesBeforeRenderer);
			}

			for (auto&& pendingPackage : packages)
			{
				channel->SendToClient(receiverClientId, pendingPackage);
			}
			channel->SendToClient(receiverClientId, package);
		}
	}

	void GuiRemoteProtocolCoreChannel::SetRendererClientId(vint clientId)
	{
		rendererClientId.store(clientId);
	}

	vint GuiRemoteProtocolCoreChannel::GetRendererClientId()
	{
		return rendererClientId.load();
	}

	void GuiRemoteProtocolCoreChannel::OnRead(vint senderClientId, const JsonPackage& package)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolCoreChannel::OnRead(vint, const JsonPackage&)#"
		CHECK_ERROR(events, ERROR_MESSAGE_PREFIX L"The protocol event receiver is not initialized.");

		ChannelPackageInfo info;
		Ptr<glr::json::JsonNode> jsonArguments;
		JsonChannelUnpack(package, info, jsonArguments);

		if (info.semantic == ChannelPackageSemantic::Event)
		{
			if (info.name == L"ControllerConnect")
			{
				SetRendererClientId(senderClientId);
			}
			else if (info.name == L"ControllerDisconnect" && GetRendererClientId() == senderClientId)
			{
				SetRendererClientId(-1);
			}
			else if (GetRendererClientId() != senderClientId)
			{
				return;
			}

			BeforeOnRead(info);
			vint index = onReadEventHandlers.Keys().IndexOf(info.name);
			if (index == -1)
			{
				CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unrecognized event name.");
			}
			else
			{
				(this->*onReadEventHandlers.Values()[index])(jsonArguments);
			}
		}
		else if (info.semantic == ChannelPackageSemantic::Response)
		{
			if (GetRendererClientId() != senderClientId)
			{
				return;
			}

			BeforeOnRead(info);
			vint index = onReadResponseHandlers.Keys().IndexOf(info.name);
			if (index == -1)
			{
				CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unrecognized response name.");
			}
			else
			{
				(this->*onReadResponseHandlers.Values()[index])(info.id, jsonArguments);
			}
		}
		else
		{
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Only events and responses are expected.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE)\
	void GuiRemoteProtocolCoreChannel::Request ## NAME()\
	{\
		Ptr<glr::json::JsonObject> package;\
		ChannelPackageInfo info{ChannelPackageSemantic::Message, -1, WString::Unmanaged(L ## #NAME)};\
		JsonChannelPack(info, {}, package);\
		BeforeWrite(info);\
		Write(package);\
	}\

#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE)\
	void GuiRemoteProtocolCoreChannel::Request ## NAME(vint id)\
	{\
		Ptr<glr::json::JsonObject> package;\
		ChannelPackageInfo info{ChannelPackageSemantic::Request, id, WString::Unmanaged(L ## #NAME)};\
		JsonChannelPack(info, {}, package);\
		BeforeWrite(info);\
		Write(package);\
	}\

#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE)\
	void GuiRemoteProtocolCoreChannel::Request ## NAME(const REQUEST& arguments)\
	{\
		Ptr<glr::json::JsonObject> package;\
		ChannelPackageInfo info{ChannelPackageSemantic::Message, -1, WString::Unmanaged(L ## #NAME)};\
		JsonChannelPack(info, ConvertCustomTypeToJson(arguments), package);\
		BeforeWrite(info);\
		Write(package);\
	}\

#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE)\
	void GuiRemoteProtocolCoreChannel::Request ## NAME(vint id, const REQUEST& arguments)\
	{\
		Ptr<glr::json::JsonObject> package;\
		ChannelPackageInfo info{ChannelPackageSemantic::Request, id, WString::Unmanaged(L ## #NAME)};\
		JsonChannelPack(info, ConvertCustomTypeToJson(arguments), package);\
		BeforeWrite(info);\
		Write(package);\
	}\

#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE)
	GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_REQ_RES
#undef MESSAGE_REQ_NORES
#undef MESSAGE_NOREQ_RES
#undef MESSAGE_NOREQ_NORES

	GuiRemoteProtocolCoreChannel::GuiRemoteProtocolCoreChannel(IJsonChannelClient* _client, IJsonChannel* _channel, const WString& _executablePath, IGuiRemoteEventProcessor* _eventProcessor)
		: client(_client)
		, channel(_channel)
		, eventProcessor(_eventProcessor)
		, executablePath(_executablePath)
	{
#define EVENT_NOREQ(NAME, REQUEST)					onReadEventHandlers.Add(WString::Unmanaged(L ## #NAME), &GuiRemoteProtocolCoreChannel::OnRead_Event_ ## NAME);
#define EVENT_REQ(NAME, REQUEST)					onReadEventHandlers.Add(WString::Unmanaged(L ## #NAME), &GuiRemoteProtocolCoreChannel::OnRead_Event_ ## NAME);
#define EVENT_HANDLER(NAME, REQUEST, REQTAG, ...)	EVENT_ ## REQTAG(NAME, REQUEST)
		GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER)
#undef EVENT_HANDLER
#undef EVENT_REQ
#undef EVENT_NOREQ

#define MESSAGE_NORES(NAME, RESPONSE)
#define MESSAGE_RES(NAME, RESPONSE)										onReadResponseHandlers.Add(WString::Unmanaged(L ## #NAME), &GuiRemoteProtocolCoreChannel::OnRead_Response_ ## NAME);
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## RESTAG(NAME, RESPONSE)
		GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_RES
#undef MESSAGE_NORES

		channel->Initialize(this);
	}

	GuiRemoteProtocolCoreChannel::~GuiRemoteProtocolCoreChannel()
	{
	}

	void GuiRemoteProtocolCoreChannel::Initialize(IGuiRemoteProtocolEvents* _events)
	{
		events = _events;
	}

	WString GuiRemoteProtocolCoreChannel::GetExecutablePath()
	{
		return executablePath;
	}
	
	void GuiRemoteProtocolCoreChannel::Submit(bool& disconnected)
	{
		auto receiverClientId = GetRendererClientId();
		List<JsonPackage> packages;
		SPIN_LOCK(lockPackagesBeforeRenderer)
		{
			packages = std::move(packagesBeforeRenderer);
		}

		if (receiverClientId == -1)
		{
			disconnected = false;
			return;
		}

		for (auto&& package : packages)
		{
			channel->SendToClient(receiverClientId, package);
		}
		channel->BatchWrite(disconnected);
	}

	IGuiRemoteEventProcessor* GuiRemoteProtocolCoreChannel::GetRemoteEventProcessor()
	{
		return eventProcessor;
	}

	void GuiRemoteProtocolCoreChannel::DetachRenderer(vint clientId)
	{
		if (GetRendererClientId() == clientId)
		{
			SetRendererClientId(-1);
		}
	}

/***********************************************************************
GuiRemoteProtocolRendererChannel
***********************************************************************/

#define EVENT_NOREQ(NAME, REQUEST)\
	void GuiRemoteProtocolRendererChannel::On ## NAME()\
	{\
		Ptr<glr::json::JsonObject> package;\
		ChannelPackageInfo info{ChannelPackageSemantic::Event, -1, WString::Unmanaged(L ## #NAME)};\
		JsonChannelPack(info, {}, package);\
		BeforeWrite(info);\
		Write(package);\
	}\

#define EVENT_REQ(NAME, REQUEST)\
	void GuiRemoteProtocolRendererChannel::On ## NAME(const REQUEST& arguments)\
	{\
		Ptr<glr::json::JsonObject> package;\
		ChannelPackageInfo info{ChannelPackageSemantic::Event, -1, WString::Unmanaged(L ## #NAME)};\
		JsonChannelPack(info, ConvertCustomTypeToJson(arguments), package);\
		BeforeWrite(info);\
		Write(package);\
	}\

#define EVENT_HANDLER(NAME, REQUEST, REQTAG, ...)						EVENT_ ## REQTAG(NAME, REQUEST)
	GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER)
#undef EVENT_HANDLER
#undef EVENT_REQ
#undef EVENT_NOREQ

#define MESSAGE_NORES(NAME, RESPONSE)
#define MESSAGE_RES(NAME, RESPONSE)\
	void GuiRemoteProtocolRendererChannel::Respond ## NAME(vint id, const RESPONSE& arguments)\
	{\
		Ptr<glr::json::JsonObject> package;\
		ChannelPackageInfo info{ChannelPackageSemantic::Response, id, WString::Unmanaged(L ## #NAME)};\
		JsonChannelPack(info, ConvertCustomTypeToJson(arguments), package);\
		BeforeWrite(info);\
		Write(package);\
	}\

#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## RESTAG(NAME, RESPONSE)
	GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_RES
#undef MESSAGE_NORES

#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE)\
	void GuiRemoteProtocolRendererChannel::Write_ ## NAME(vint id, Ptr<glr::json::JsonNode> jsonArguments)\
	{\
		protocol->Request ## NAME();\
	}\

#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE)\
	void GuiRemoteProtocolRendererChannel::Write_ ## NAME(vint id, Ptr<glr::json::JsonNode> jsonArguments)\
	{\
		protocol->Request ## NAME(id);\
	}\

#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE)\
	void GuiRemoteProtocolRendererChannel::Write_ ## NAME(vint id, Ptr<glr::json::JsonNode> jsonArguments)\
	{\
		REQUEST arguments;\
		ConvertJsonToCustomType(jsonArguments, arguments);\
		protocol->Request ## NAME(arguments);\
	}\

#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE)\
	void GuiRemoteProtocolRendererChannel::Write_ ## NAME(vint id, Ptr<glr::json::JsonNode> jsonArguments)\
	{\
		REQUEST arguments;\
		ConvertJsonToCustomType(jsonArguments, arguments);\
		protocol->Request ## NAME(id, arguments);\
	}\

#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE)
	GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_REQ_RES
#undef MESSAGE_REQ_NORES
#undef MESSAGE_NOREQ_RES
#undef MESSAGE_NOREQ_NORES

	void GuiRemoteProtocolRendererChannel::Write(Ptr<glr::json::JsonObject> package)
	{
		channel->SendToClient(GacUIRemoteProtocolCoreClientId, package);

		if (!receiving)
		{
			bool disconnected = false;
			Flush(disconnected);
		}
	}

	void GuiRemoteProtocolRendererChannel::Flush(bool& disconnected)
	{
		channel->BatchWrite(disconnected);
	}

	void GuiRemoteProtocolRendererChannel::OnRead(vint senderClientId, const JsonPackage& package)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolRendererChannel::OnRead(vint, const JsonPackage&)#"
		ChannelPackageInfo info;
		Ptr<glr::json::JsonNode> jsonArguments;
		JsonChannelUnpack(package, info, jsonArguments);
		BeforeOnRead(info);

		if (info.semantic != ChannelPackageSemantic::Message && info.semantic != ChannelPackageSemantic::Request)
		{
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Only messages and requests are expected.");
		}

		vint index = writeHandlers.Keys().IndexOf(info.name);
		if (index == -1)
		{
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unrecognized request name.");
		}
		else
		{
			receiving = true;
			(this->*writeHandlers.Values()[index])(info.id, jsonArguments);
			receiving = false;

			bool disconnected = false;
			Flush(disconnected);
		}
#undef ERROR_MESSAGE_PREFIX
	}

	GuiRemoteProtocolRendererChannel::GuiRemoteProtocolRendererChannel(IJsonChannel* _channel, IGuiRemoteProtocol* _protocol)
		: channel(_channel)
		, protocol(_protocol)
	{
#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE)					writeHandlers.Add(WString::Unmanaged(L ## #NAME), &GuiRemoteProtocolRendererChannel::Write_ ## NAME);
#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE)						writeHandlers.Add(WString::Unmanaged(L ## #NAME), &GuiRemoteProtocolRendererChannel::Write_ ## NAME);
#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE)						writeHandlers.Add(WString::Unmanaged(L ## #NAME), &GuiRemoteProtocolRendererChannel::Write_ ## NAME);
#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE)						writeHandlers.Add(WString::Unmanaged(L ## #NAME), &GuiRemoteProtocolRendererChannel::Write_ ## NAME);
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE)
		GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_REQ_RES
#undef MESSAGE_REQ_NORES
#undef MESSAGE_NOREQ_RES
#undef MESSAGE_NOREQ_NORES

		channel->Initialize(this);
		protocol->Initialize(this);
	}

	GuiRemoteProtocolRendererChannel::~GuiRemoteProtocolRendererChannel()
	{
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_DOMDIFF.CPP
***********************************************************************/

namespace vl::presentation::remoteprotocol
{

/***********************************************************************
GuiRemoteEventDomDiffConverter
***********************************************************************/

	GuiRemoteEventDomDiffConverter::GuiRemoteEventDomDiffConverter()
	{
	}

	GuiRemoteEventDomDiffConverter::~GuiRemoteEventDomDiffConverter()
	{
	}

	void GuiRemoteEventDomDiffConverter::OnControllerConnect(const remoteprotocol::ControllerGlobalConfig& arguments)
	{
		lastDom = {};
		TBase::OnControllerConnect(arguments);
	}

/***********************************************************************
GuiRemoteProtocolDomDiffConverter
***********************************************************************/

	GuiRemoteProtocolDomDiffConverter::GuiRemoteProtocolDomDiffConverter(IGuiRemoteProtocol* _protocol)
		: TBase(_protocol)
	{
	}

	GuiRemoteProtocolDomDiffConverter::~GuiRemoteProtocolDomDiffConverter()
	{
	}

	void GuiRemoteProtocolDomDiffConverter::RequestRendererBeginRendering(const remoteprotocol::ElementBeginRendering& arguments)
	{
		renderingDomBuilder.RequestRendererBeginRendering();
		TBase::RequestRendererBeginRendering(arguments);
	}

	void GuiRemoteProtocolDomDiffConverter::RequestRendererEndRendering(vint id)
	{
		auto dom = renderingDomBuilder.RequestRendererEndRendering();
		DomIndex domIndex;
		BuildDomIndex(dom, domIndex);

		if (eventCombinator.lastDom)
		{
			RenderingDom_DiffsInOrder diffs;
			DiffDom(eventCombinator.lastDom, eventCombinator.lastDomIndex, dom, domIndex, diffs);
			targetProtocol->RequestRendererRenderDomDiff(diffs);
		}
		else
		{
			targetProtocol->RequestRendererRenderDom(dom);
		}

		eventCombinator.lastDom = dom;
		eventCombinator.lastDomIndex = std::move(domIndex);
		TBase::RequestRendererEndRendering(id);
	}

	void GuiRemoteProtocolDomDiffConverter::RequestRendererBeginBoundary(const remoteprotocol::ElementBoundary& arguments)
	{
		renderingDomBuilder.RequestRendererBeginBoundary(arguments);
	}

	void GuiRemoteProtocolDomDiffConverter::RequestRendererEndBoundary()
	{
		renderingDomBuilder.RequestRendererEndBoundary();
	}

	void GuiRemoteProtocolDomDiffConverter::RequestRendererRenderElement(const remoteprotocol::ElementRendering& arguments)
	{
		renderingDomBuilder.RequestRendererRenderElement(arguments);
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_FILTER.CPP
***********************************************************************/

namespace vl::presentation::remoteprotocol::repeatfiltering
{

/***********************************************************************
GuiRemoteEventFilter
***********************************************************************/

	GuiRemoteEventFilter::GuiRemoteEventFilter()
	{
	}

	GuiRemoteEventFilter::~GuiRemoteEventFilter()
	{
	}

	void GuiRemoteEventFilter::ProcessResponses()
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::repeatfiltering::GuiRemoteProtocolFilter::ProcessResponses()#"
		for (auto&& response : filteredResponses)
		{
#define MESSAGE_NORES(NAME, RESPONSE)
#define MESSAGE_RES(NAME, RESPONSE)\
			case FilteredResponseNames::NAME:\
				targetEvents->Respond ## NAME(response.id, response.arguments.Get<RESPONSE>());\
				break;\
	
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## RESTAG(NAME, RESPONSE)
			switch (response.name)
			{
			GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
			default:
				CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unrecognized response.");
			}
#undef MESSAGE_HANDLER
#undef MESSAGE_RES
#undef MESSAGE_NORES
		}

		CHECK_ERROR(responseIds.Count() == 0, ERROR_MESSAGE_PREFIX L"Messages sending to IGuiRemoteProtocol should be all responded.");
		filteredResponses.Clear();
#undef ERROR_MESSAGE_PREFIX
	}
	
	void GuiRemoteEventFilter::ProcessEvents()
	{
#define EVENT_NODROP(NAME)
#define EVENT_DROPREP(NAME)									lastDropRepeatEvent ## NAME = -1;
#define EVENT_DROPCON(NAME)									lastDropConsecutiveEvent ## NAME = -1;
#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...)	EVENT_ ## DROPTAG(NAME)
		GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER)
#undef EVENT_HANDLER
#undef EVENT_DROPCON
#undef EVENT_DROPREP
#undef EVENT_NODROP
	
		collections::List<FilteredEvent> events(std::move(filteredEvents));
	
		for (auto&& event : events)
		{
			if (event.dropped)
			{
				continue;
			}
	
#define EVENT_NOREQ(NAME, REQUEST)\
			case FilteredEventNames::NAME:\
				targetEvents->On ## NAME();\
				break;\
	
#define EVENT_REQ(NAME, REQUEST)\
			case FilteredEventNames::NAME:\
				targetEvents->On ## NAME(event.arguments.Get<REQUEST>());\
				break;\
	
#define EVENT_HANDLER(NAME, REQUEST, REQTAG, ...)	EVENT_ ## REQTAG(NAME, REQUEST)
			switch (event.name)
			{
			GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER)
			default:
				CHECK_FAIL(L"vl::presentation::remoteprotocol::GuiRemoteEventFilter::ProcessEvents()#Unrecognized event.");
			}
#undef EVENT_HANDLER
#undef EVENT_REQ
#undef EVENT_NOREQ
		}
	}

	// responses

#define MESSAGE_NORES(NAME, RESPONSE)
#define MESSAGE_RES(NAME, RESPONSE)\
	void GuiRemoteEventFilter::Respond ## NAME(vint id, const RESPONSE& arguments)\
	{\
		CHECK_ERROR(\
			responseIds[id] == FilteredResponseNames::NAME,\
			L"vl::presentation::remoteprotocol::GuiRemoteEventFilter::"\
			L"Respond" L ## #NAME L"()#"\
			L"Messages sending to IGuiRemoteProtocol should be responded by calling the correct function.");\
		responseIds.Remove(id);\
		FilteredResponse response;\
		response.id = id;\
		response.name = FilteredResponseNames::NAME;\
		response.arguments = arguments;\
		filteredResponses.Add(response);\
	}\
	
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## RESTAG(NAME, RESPONSE)
		GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_RES
#undef MESSAGE_NORES

	// events
	
#define EVENT_NODROP(NAME)
	
#define EVENT_DROPREP(NAME)\
		if (lastDropRepeatEvent ## NAME != -1)\
		{\
			filteredEvents[lastDropRepeatEvent ## NAME].dropped = true;\
		}\
		lastDropRepeatEvent ## NAME = filteredEvents.Count() - 1\
	
#define EVENT_DROPCON(NAME)\
		if (lastDropConsecutiveEvent ## NAME != -1 && lastDropConsecutiveEvent ## NAME == filteredEvents.Count() - 1)\
		{\
			filteredEvents[lastDropConsecutiveEvent ## NAME].dropped = true;\
		}\
		lastDropConsecutiveEvent ## NAME = filteredEvents.Count() - 1\
	
#define EVENT_NOREQ(NAME, REQUEST, DROPTAG)\
	void GuiRemoteEventFilter::On ## NAME()\
	{\
		if (submitting)\
		{\
			EVENT_ ## DROPTAG(NAME);\
			FilteredEvent event;\
			event.name = FilteredEventNames::NAME;\
			filteredEvents.Add(event);\
		}\
		else\
		{\
			targetEvents->On ## NAME();\
		}\
	}\
	
#define EVENT_REQ(NAME, REQUEST, DROPTAG)\
	void GuiRemoteEventFilter::On ## NAME(const REQUEST& arguments)\
	{\
		if (submitting)\
		{\
			EVENT_ ## DROPTAG(NAME);\
			FilteredEvent event;\
			event.name = FilteredEventNames::NAME;\
			event.arguments = arguments;\
			filteredEvents.Add(event);\
		}\
		else\
		{\
			targetEvents->On ## NAME(arguments);\
		}\
	}\
	
#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...)	EVENT_ ## REQTAG(NAME, REQUEST, DROPTAG)
	GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER)
#undef EVENT_HANDLER
#undef EVENT_REQ
#undef EVENT_NOREQ
#undef EVENT_DROPCON
#undef EVENT_DROPREP
#undef EVENT_NOREP

/***********************************************************************
GuiRemoteProtocolFilter
***********************************************************************/

	void GuiRemoteProtocolFilter::ProcessRequests()
	{
#define MESSAGE_NODROP(NAME)
#define MESSAGE_DROPREP(NAME)												lastDropRepeatRequest ## NAME = -1;
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG)	MESSAGE_ ## DROPTAG(NAME)
		GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_DROPREP
#undef MESSAGE_NODROP
	
		for (auto&& request : filteredRequests)
		{
			CHECK_ERROR(\
				!request.dropped || request.id == -1,\
				L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::ProcessRequests()#"\
				L"Messages with id cannot be dropped.");\
			if (request.dropped)
			{
				continue;
			}
	
#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE)\
			case FilteredRequestNames::NAME:\
				targetProtocol->Request ## NAME();\
				break;\
	
#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE)\
			case FilteredRequestNames::NAME:\
				targetProtocol->Request ## NAME(request.id);\
				break;\
	
#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE)\
			case FilteredRequestNames::NAME:\
				targetProtocol->Request ## NAME(request.arguments.Get<REQUEST>());\
				break;\
	
#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE)\
			case FilteredRequestNames::NAME:\
				targetProtocol->Request ## NAME(request.id, request.arguments.Get<REQUEST>());\
				break;\
	
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE)
			switch (request.name)
			{
			GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
			default:
				CHECK_FAIL(L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::ProcessRequests()#Unrecognized request.");
			}
#undef MESSAGE_HANDLER
#undef MESSAGE_REQ_RES
#undef MESSAGE_REQ_NORES
#undef MESSAGE_NOREQ_RES
#undef MESSAGE_NOREQ_NORES
		}
	
		filteredRequests.Clear();
	}

	GuiRemoteProtocolFilter::GuiRemoteProtocolFilter(IGuiRemoteProtocol* _protocol)
		: GuiRemoteProtocolCombinator<GuiRemoteEventFilter>(_protocol)
	{
	}

	GuiRemoteProtocolFilter::~GuiRemoteProtocolFilter()
	{
	}
	
	// messages
	
#define MESSAGE_NODROP(NAME)
	
#define MESSAGE_DROPREP(NAME)\
		if (lastDropRepeatRequest ## NAME != -1)\
		{\
			filteredRequests[lastDropRepeatRequest ## NAME].dropped = true;\
		}\
		lastDropRepeatRequest ## NAME = filteredRequests.Count()\
	
#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\
	void GuiRemoteProtocolFilter::Request ## NAME()\
	{\
		MESSAGE_ ## DROPTAG(NAME);\
		FilteredRequest request;\
		request.name = FilteredRequestNames::NAME;\
		filteredRequests.Add(request);\
	}\
	
#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\
	void GuiRemoteProtocolFilter::Request ## NAME(vint id)\
	{\
		MESSAGE_ ## DROPTAG(NAME);\
		CHECK_ERROR(\
			lastRequestId < id,\
			L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::"\
			L"Request" L ## #NAME L"()#"\
			L"Id of a message sending to IGuiRemoteProtocol should be increasing.");\
		lastRequestId = id;\
		FilteredRequest request;\
		request.id = id;\
		request.name = FilteredRequestNames::NAME;\
		filteredRequests.Add(request);\
		eventCombinator.responseIds.Add(id, FilteredResponseNames::NAME);\
	}\
	
#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\
	void GuiRemoteProtocolFilter::Request ## NAME(const REQUEST& arguments)\
	{\
		MESSAGE_ ## DROPTAG(NAME);\
		FilteredRequest request;\
		request.name = FilteredRequestNames::NAME;\
		request.arguments = arguments;\
		filteredRequests.Add(request);\
	}\
	
#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\
	void GuiRemoteProtocolFilter::Request ## NAME(vint id, const REQUEST& arguments)\
	{\
		MESSAGE_ ## DROPTAG(NAME);\
		CHECK_ERROR(\
			lastRequestId < id,\
			L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::"\
			L"Request" L ## #NAME L"()#"\
			L"Id of a message sending to IGuiRemoteProtocol should be increasing.");\
		lastRequestId = id;\
		FilteredRequest request;\
		request.id = id;\
		request.name = FilteredRequestNames::NAME;\
		request.arguments = arguments;\
		filteredRequests.Add(request);\
		eventCombinator.responseIds.Add(id, FilteredResponseNames::NAME);\
	}\
	
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG, ...)	MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE, DROPTAG)
	GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_REQ_RES
#undef MESSAGE_REQ_NORES
#undef MESSAGE_NOREQ_RES
#undef MESSAGE_NOREQ_NORES
#undef MESSAGE_DROPREP
#undef MESSAGE_NODROP
	
	// protocol
	
	void GuiRemoteProtocolFilter::Initialize(IGuiRemoteProtocolEvents* _events)
	{
		if (auto verifierProtocol = dynamic_cast<GuiRemoteProtocolFilterVerifier*>(targetProtocol))
		{
			verifierProtocol->targetProtocol->Initialize(&eventCombinator);
			eventCombinator.targetEvents = &verifierProtocol->eventCombinator;
			verifierProtocol->eventCombinator.targetEvents = _events;
		}
		else
		{
			GuiRemoteProtocolCombinator<GuiRemoteEventFilter>::Initialize(_events);
		}
	}
	
	void GuiRemoteProtocolFilter::Submit(bool& disconnected)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::repeatfiltering::GuiRemoteProtocolFilter::Submit()#"
		CHECK_ERROR(!eventCombinator.submitting, ERROR_MESSAGE_PREFIX L"This function is not allowed to be called recursively.");
		eventCombinator.submitting = true;
		ProcessRequests();
		GuiRemoteProtocolCombinator<GuiRemoteEventFilter>::Submit(disconnected);
		if (disconnected)
		{
			eventCombinator.responseIds.Clear();
		}
		else
		{
			eventCombinator.ProcessResponses();
		}
		eventCombinator.submitting = false;
		eventCombinator.ProcessEvents();
#undef ERROR_MESSAGE_PREFIX
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_FILTERVERIFIER.CPP
***********************************************************************/

namespace vl::presentation::remoteprotocol::repeatfiltering
{
/***********************************************************************
GuiRemoteEventFilterVerifier
***********************************************************************/

	GuiRemoteEventFilterVerifier::GuiRemoteEventFilterVerifier()
	{
	}

	GuiRemoteEventFilterVerifier::~GuiRemoteEventFilterVerifier()
	{
	}

	void GuiRemoteEventFilterVerifier::ClearDropRepeatMasks()
	{
#define EVENT_NODROP(NAME)
#define EVENT_DROPREP(NAME)									lastDropRepeatEvent ## NAME = false;
#define EVENT_DROPCON(NAME)
#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...)	EVENT_ ## DROPTAG(NAME)
		GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER)
#undef EVENT_HANDLER
#undef EVENT_DROPCON
#undef EVENT_DROPREP
#undef EVENT_NODROP
	}

	void GuiRemoteEventFilterVerifier::ClearDropConsecutiveMasks()
	{
#define EVENT_NODROP(NAME)
#define EVENT_DROPREP(NAME)
#define EVENT_DROPCON(NAME)									lastDropConsecutiveEvent ## NAME = false;
#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...)	EVENT_ ## DROPTAG(NAME)
		GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER)
#undef EVENT_HANDLER
#undef EVENT_DROPCON
#undef EVENT_DROPREP
#undef EVENT_NODROP
	}

	// responses

#define MESSAGE_NORES(NAME, RESPONSE)
#define MESSAGE_RES(NAME, RESPONSE)\
	void GuiRemoteEventFilterVerifier::Respond ## NAME(vint id, const RESPONSE& arguments)\
	{\
		targetEvents->Respond ## NAME(id, arguments);\
	}\
	
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...)	MESSAGE_ ## RESTAG(NAME, RESPONSE)
		GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_RES
#undef MESSAGE_NORES

	// events
	
#define EVENT_NODROP(NAME)
	
#define EVENT_DROPREP(NAME)\
		CHECK_ERROR(!lastDropRepeatEvent ## NAME, L"vl::presentation::remoteprotocol::GuiRemoteEventFilterVerifier::On" L ## #NAME L"(...)#[@DropRepeat] event repeated.");\
		lastDropRepeatEvent ## NAME = true;\
	
#define EVENT_DROPCON(NAME)\
		CHECK_ERROR(!lastDropConsecutiveEvent ## NAME, L"vl::presentation::remoteprotocol::GuiRemoteEventFilterVerifier::On" L ## #NAME L"(...)#[@DropConsecutive] event repeated.");\
		ClearDropConsecutiveMasks();\
		lastDropConsecutiveEvent ## NAME = true;\
	
#define EVENT_NOREQ(NAME, REQUEST, DROPTAG)\
	void GuiRemoteEventFilterVerifier::On ## NAME()\
	{\
		if (submitting)\
		{\
			EVENT_ ## DROPTAG(NAME);\
			targetEvents->On ## NAME();\
		}\
		else\
		{\
			targetEvents->On ## NAME();\
		}\
	}\
	
#define EVENT_REQ(NAME, REQUEST, DROPTAG)\
	void GuiRemoteEventFilterVerifier::On ## NAME(const REQUEST& arguments)\
	{\
		if (submitting)\
		{\
			EVENT_ ## DROPTAG(NAME);\
			targetEvents->On ## NAME(arguments);\
		}\
		else\
		{\
			targetEvents->On ## NAME(arguments);\
		}\
	}\
	
#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...)	EVENT_ ## REQTAG(NAME, REQUEST, DROPTAG)
	GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER)
#undef EVENT_HANDLER
#undef EVENT_REQ
#undef EVENT_NOREQ
#undef EVENT_DROPCON
#undef EVENT_DROPREP
#undef EVENT_NOREP

/***********************************************************************
GuiRemoteProtocolFilterVerifier
***********************************************************************/

	void GuiRemoteProtocolFilterVerifier::ClearDropRepeatMasks()
	{
#define MESSAGE_NODROP(NAME)
#define MESSAGE_DROPREP(NAME)												lastDropRepeatRequest ## NAME = false;
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG)	MESSAGE_ ## DROPTAG(NAME)
		GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_DROPREP
#undef MESSAGE_NODROP
	}

	GuiRemoteProtocolFilterVerifier::GuiRemoteProtocolFilterVerifier(IGuiRemoteProtocol* _protocol)
		: GuiRemoteProtocolCombinator<GuiRemoteEventFilterVerifier>(_protocol)
	{
	}

	GuiRemoteProtocolFilterVerifier::~GuiRemoteProtocolFilterVerifier()
	{
	}
	
	// messages
	
#define MESSAGE_NODROP(NAME)
	
#define MESSAGE_DROPREP(NAME)\
		CHECK_ERROR(!lastDropRepeatRequest ## NAME, L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilterVerifier::Request" L ## #NAME L"(...)#[@DropRepeat] message repeated.");\
		lastDropRepeatRequest ## NAME = true;\
	
#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\
	void GuiRemoteProtocolFilterVerifier::Request ## NAME()\
	{\
		MESSAGE_ ## DROPTAG(NAME);\
		targetProtocol->Request ## NAME();\
	}\
	
#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\
	void GuiRemoteProtocolFilterVerifier::Request ## NAME(vint id)\
	{\
		MESSAGE_ ## DROPTAG(NAME);\
		targetProtocol->Request ## NAME(id);\
	}\
	
#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\
	void GuiRemoteProtocolFilterVerifier::Request ## NAME(const REQUEST& arguments)\
	{\
		MESSAGE_ ## DROPTAG(NAME);\
		targetProtocol->Request ## NAME(arguments);\
	}\
	
#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\
	void GuiRemoteProtocolFilterVerifier::Request ## NAME(vint id, const REQUEST& arguments)\
	{\
		MESSAGE_ ## DROPTAG(NAME);\
		targetProtocol->Request ## NAME(id, arguments);\
	}\
	
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG, ...)	MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE, DROPTAG)
	GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
#undef MESSAGE_HANDLER
#undef MESSAGE_REQ_RES
#undef MESSAGE_REQ_NORES
#undef MESSAGE_NOREQ_RES
#undef MESSAGE_NOREQ_NORES
#undef MESSAGE_DROPREP
#undef MESSAGE_NODROP
	
	// protocol
	
	void GuiRemoteProtocolFilterVerifier::Submit(bool& disconnected)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::repeatfiltering::GuiRemoteProtocolFilterVerifier::Submit()#"
		CHECK_ERROR(!eventCombinator.submitting, ERROR_MESSAGE_PREFIX L"This function is not allowed to be called recursively.");
		eventCombinator.submitting = true;
		GuiRemoteProtocolCombinator<GuiRemoteEventFilterVerifier>::Submit(disconnected);
		ClearDropRepeatMasks();
		eventCombinator.ClearDropRepeatMasks();
		eventCombinator.ClearDropConsecutiveMasks();
		eventCombinator.submitting = false;
#undef ERROR_MESSAGE_PREFIX
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEWINDOW.CPP
***********************************************************************/

namespace vl::presentation
{
/***********************************************************************
GuiRemoteWindow
***********************************************************************/

#define SET_REMOTE_WINDOW_STYLE(STYLE, VALUE)\
		if (style ## STYLE != VALUE)\
		{\
			style ## STYLE = VALUE;\
			remoteMessages.RequestWindowNotifySet ## STYLE(VALUE);\
		}\

#define SET_REMOTE_WINDOW_STYLE_INVALIDATE(STYLE, VALUE)\
		if (style ## STYLE != VALUE)\
		{\
			style ## STYLE = VALUE;\
			sizingConfigInvalidated = true;\
			remoteMessages.RequestWindowNotifySet ## STYLE(VALUE);\
		}\

	void GuiRemoteWindow::RequestGetBounds()
	{
		remote->EnsureControllerConnected();
		vint idGetBounds = remoteMessages.RequestWindowGetBounds();
		bool disconnected = false;
		remoteMessages.Submit(disconnected);
		if (disconnected) return;
		sizingConfigInvalidated = false;
		OnWindowBoundsUpdated(remoteMessages.RetrieveWindowGetBounds(idGetBounds));
	}

	void GuiRemoteWindow::Opened()
	{
		if (!statusVisible)
		{
			statusVisible = true;
			for (auto l : listeners)l->Opened();
		}
	}

	void GuiRemoteWindow::SetActivated(bool activated)
	{
		if (statusActivated != activated)
		{
			statusActivated = activated;
			if (statusActivated)
			{
				for (auto l : listeners)l->GotFocus();
				for (auto l : listeners)l->RenderingAsActivated();
			}
			else
			{
				for (auto l : listeners)l->LostFocus();
				for (auto l : listeners)l->RenderingAsDeactivated();
			}
		}
	}

	void GuiRemoteWindow::ShowWithSizeState(bool activate, INativeWindow::WindowSizeState sizeState)
	{
		remote->EnsureControllerConnected();
		if (!statusVisible || remoteWindowSizingConfig.sizeState != sizeState)
		{
			remoteprotocol::WindowShowing windowShowing;
			windowShowing.activate = activate;
			windowShowing.sizeState = sizeState;
			remoteMessages.RequestWindowNotifyShow(windowShowing);
			bool disconnected = false;
			remoteMessages.Submit(disconnected);
			// there is no result from this request, assuming succeeded

			remoteWindowSizingConfig.sizeState = sizeState;
			Opened();
			SetActivated(activate);
		}
		else if (!statusActivated && activate)
		{
			SetActivate();
		}
	}

	void GuiRemoteWindow::SubmitStateAfterControllerConnect()
	{
		remoteMessages.RequestWindowNotifySetTitle(styleTitle);
		remoteMessages.RequestWindowNotifySetEnabled(styleEnabled);
		remoteMessages.RequestWindowNotifySetTopMost(styleTopMost);
		remoteMessages.RequestWindowNotifySetShowInTaskBar(styleShowInTaskBar);
		remoteMessages.RequestWindowNotifySetCustomFrameMode(styleCustomFrameMode);
		remoteMessages.RequestWindowNotifySetMaximizedBox(styleMaximizedBox);
		remoteMessages.RequestWindowNotifySetMinimizedBox(styleMinimizedBox);
		remoteMessages.RequestWindowNotifySetBorder(styleBorder);
		remoteMessages.RequestWindowNotifySetSizeBox(styleSizeBox);
		remoteMessages.RequestWindowNotifySetIconVisible(styleIconVisible);
		remoteMessages.RequestWindowNotifySetTitleBar(styleTitleBar);
		if (suggestedMinClientSize != NativeSize{ {0},{0} })
		{
			// The renderer calculates its outer minimum from the current
			// native frame. Apply frame styles first so reconnecting from a
			// platform-default window does not include stale decorations.
			remoteMessages.RequestWindowNotifyMinSize(suggestedMinClientSize);
		}
		if (statusCapturing)
		{
			remoteMessages.RequestIORequireCapture();
		}
		else
		{
			remoteMessages.RequestIOReleaseCapture();
		}
		bool disconnected = false;
		remoteMessages.Submit(disconnected);
		// there is no result from these requests, assuming succeeded
	}

/***********************************************************************
GuiRemoteWindow (events)
***********************************************************************/

	void GuiRemoteWindow::OnControllerConnect()
	{
		if (controllerDisconnected)
		{
			controllerDisconnected = false;
		}

		scalingX = remote->remoteScreenConfig.scalingX;
		scalingY = remote->remoteScreenConfig.scalingY;

		auto bounds = remoteWindowSizingConfig.bounds;
		if (remote->applicationRunning)
		{
			// A replacement renderer creates its native window with platform
			// defaults. Restore the application frame style before applying
			// the saved bounds so client-size calculations use the right frame.
			// Style changes report the renderer's temporary bounds back to the
			// core, so keep the saved bounds in a local variable.
			SubmitStateAfterControllerConnect();
		}

		sizingConfigInvalidated = true;
		remoteMessages.RequestWindowNotifySetBounds(bounds);
		RequestGetBounds();

		// TODO:
		//   This is a workaround to call GuiWindow::UpdateCustomFramePadding
		//   Refactor to make it more elegant.
		for (auto l : listeners) l->DpiChanged(true);
		for (auto l : listeners) l->DpiChanged(false);
	}

	void GuiRemoteWindow::OnControllerDisconnect()
	{
		controllerDisconnected = true;
	}

	void GuiRemoteWindow::OnControllerScreenUpdated(const remoteprotocol::ScreenConfig& arguments)
	{
		if (scalingX != arguments.scalingX || scalingY != arguments.scalingY)
		{
			scalingX = arguments.scalingX;
			scalingY = arguments.scalingY;
			for (auto l : listeners) l->DpiChanged(true);
			for (auto l : listeners) l->DpiChanged(false);
		}
	}

	void GuiRemoteWindow::OnWindowBoundsUpdated(const remoteprotocol::WindowSizingConfig& arguments)
	{
		bool callMoved = false;
		if (remoteWindowSizingConfig.bounds != arguments.bounds ||
			remoteWindowSizingConfig.clientBounds != arguments.clientBounds)
		{
			callMoved = true;
		}

		remoteWindowSizingConfig = arguments;
		if(callMoved)
		{
			for (auto l : listeners) l->Moved();
		}
	}

	void GuiRemoteWindow::OnWindowActivatedUpdated(bool activated)
	{
		SetActivated(activated);
	}

/***********************************************************************
GuiRemoteWindow
***********************************************************************/

	GuiRemoteWindow::GuiRemoteWindow(GuiRemoteController* _remote)
		: remote(_remote)
		, remoteMessages(_remote->remoteMessages)
		, remoteEvents(_remote->remoteEvents)
	{
		remoteWindowSizingConfig.sizeState = INativeWindow::Restored;
	}

	GuiRemoteWindow::~GuiRemoteWindow()
	{
	}

/***********************************************************************
GuiRemoteWindow (INativeWindow)
***********************************************************************/

	bool GuiRemoteWindow::IsActivelyRefreshing()
	{
		return true;
	}

	NativeSize GuiRemoteWindow::GetRenderingOffset()
	{
		return { 0,0 };
	}

	Point GuiRemoteWindow::Convert(NativePoint value)
	{
		return Point((vint)(value.x.value / scalingX), (vint)(value.y.value / scalingY));
	}

	NativePoint GuiRemoteWindow::Convert(Point value)
	{
		return NativePoint((vint)(value.x * scalingX), (vint)(value.y * scalingY));
	}

	Size GuiRemoteWindow::Convert(NativeSize value)
	{
		return Size((vint)(value.x.value / scalingX), (vint)(value.y.value / scalingY));
	}

	NativeSize GuiRemoteWindow::Convert(Size value)
	{
		return NativeSize((vint)(value.x * scalingX), (vint)(value.y * scalingY));
	}

	Margin GuiRemoteWindow::Convert(NativeMargin value)
	{
		return Margin(
			(vint)(value.left.value / scalingX),
			(vint)(value.top.value / scalingY),
			(vint)(value.right.value / scalingX),
			(vint)(value.bottom.value / scalingY)
		);
	}

	NativeMargin GuiRemoteWindow::Convert(Margin value)
	{
		return NativeMargin(
			(vint)(value.left * scalingX),
			(vint)(value.top * scalingY),
			(vint)(value.right * scalingX),
			(vint)(value.bottom * scalingY)
		);
	}

	NativeRect GuiRemoteWindow::GetBounds()
	{
		if (sizingConfigInvalidated) RequestGetBounds();
		return remoteWindowSizingConfig.bounds;
	}

	void GuiRemoteWindow::SetBounds(const NativeRect& bounds)
	{
		if (remoteWindowSizingConfig.bounds != bounds)
		{
			auto x1 = remoteWindowSizingConfig.clientBounds.x1 - remoteWindowSizingConfig.bounds.x1;
			auto y1 = remoteWindowSizingConfig.clientBounds.y1 - remoteWindowSizingConfig.bounds.y1;
			auto x2 = remoteWindowSizingConfig.clientBounds.x2 - remoteWindowSizingConfig.bounds.x2;
			auto y2 = remoteWindowSizingConfig.clientBounds.y2 - remoteWindowSizingConfig.bounds.y2;
			remoteWindowSizingConfig.bounds = bounds;
			remoteWindowSizingConfig.clientBounds = {
				x1 + remoteWindowSizingConfig.bounds.x1,
				y1 + remoteWindowSizingConfig.bounds.y1,
				x2 + remoteWindowSizingConfig.bounds.x2,
				y2 + remoteWindowSizingConfig.bounds.y2
			};
			remoteMessages.RequestWindowNotifySetBounds(bounds);
			sizingConfigInvalidated = true;
		}
	}

	NativeSize GuiRemoteWindow::GetClientSize()
	{
		if (sizingConfigInvalidated) RequestGetBounds();
		return remoteWindowSizingConfig.clientBounds.GetSize();
	}

	void GuiRemoteWindow::SetClientSize(NativeSize size)
	{
		if (remoteWindowSizingConfig.clientBounds.GetSize() != size)
		{
			auto x1 = remoteWindowSizingConfig.bounds.x1 - remoteWindowSizingConfig.clientBounds.x1;
			auto y1 = remoteWindowSizingConfig.bounds.y1 - remoteWindowSizingConfig.clientBounds.y1;
			auto x2 = remoteWindowSizingConfig.bounds.x2 - remoteWindowSizingConfig.clientBounds.x2;
			auto y2 = remoteWindowSizingConfig.bounds.y2 - remoteWindowSizingConfig.clientBounds.y2;
			remoteWindowSizingConfig.clientBounds = { remoteWindowSizingConfig.clientBounds.LeftTop(),size };
			remoteWindowSizingConfig.bounds = {
				x1 + remoteWindowSizingConfig.clientBounds.x1,
				y1 + remoteWindowSizingConfig.clientBounds.y1,
				x2 + remoteWindowSizingConfig.clientBounds.x2,
				y2 + remoteWindowSizingConfig.clientBounds.y2
			};
			remoteMessages.RequestWindowNotifySetClientSize(size);
			sizingConfigInvalidated = true;
		}
	}

	NativeRect GuiRemoteWindow::GetClientBoundsInScreen()
	{
		auto bounds = remoteWindowSizingConfig.clientBounds;
		bounds.x1.value += remoteWindowSizingConfig.bounds.x1.value;
		bounds.y1.value += remoteWindowSizingConfig.bounds.y1.value;
		bounds.x2.value += remoteWindowSizingConfig.bounds.x1.value;
		bounds.y2.value += remoteWindowSizingConfig.bounds.y1.value;
		return bounds;
	}

	void GuiRemoteWindow::SuggestMinClientSize(NativeSize size)
	{
		if (suggestedMinClientSize != size)
		{
			suggestedMinClientSize = size;
			remoteMessages.RequestWindowNotifyMinSize(suggestedMinClientSize);
		}
	}

	WString GuiRemoteWindow::GetTitle()
	{
		return styleTitle;
	}

	void GuiRemoteWindow::SetTitle(const WString& title)
	{
		SET_REMOTE_WINDOW_STYLE(Title, title);
	}

	INativeCursor* GuiRemoteWindow::GetWindowCursor()
	{
		if (!styleCursor)
		{
			styleCursor = remote->ResourceService()->GetDefaultSystemCursor();
		}
		return styleCursor;
	}

	void GuiRemoteWindow::SetWindowCursor(INativeCursor* cursor)
	{
		styleCursor = cursor;
	}

	NativePoint GuiRemoteWindow::GetCaretPoint()
	{
		return styleCaret;
	}

	void GuiRemoteWindow::SetCaretPoint(NativePoint point)
	{
		styleCaret = point;
		remoteMessages.RequestWindowNotifySetCaret(point);
	}

	INativeWindow* GuiRemoteWindow::GetParent()
	{
		return nullptr;
	}

	void GuiRemoteWindow::SetParent(INativeWindow* parent)
	{
		CHECK_FAIL(L"vl::presentation::GuiRemoteWindow::SetParent(INativeWindow*)#GuiHostedController is not supposed to call this.");
	}

	INativeWindow::WindowMode GuiRemoteWindow::GetWindowMode()
	{
		return windowMode;
	}

	void GuiRemoteWindow::EnableCustomFrameMode()
	{
		SET_REMOTE_WINDOW_STYLE_INVALIDATE(CustomFrameMode, true);
	}

	void GuiRemoteWindow::DisableCustomFrameMode()
	{
		SET_REMOTE_WINDOW_STYLE_INVALIDATE(CustomFrameMode, false);
	}

	bool GuiRemoteWindow::IsCustomFrameModeEnabled()
	{
		return styleCustomFrameMode;
	}

	NativeMargin GuiRemoteWindow::GetCustomFramePadding()
	{
		return remoteWindowSizingConfig.customFramePadding;
	}

	Ptr<GuiImageData> GuiRemoteWindow::GetIcon()
	{
		return styleIcon;
	}

	void GuiRemoteWindow::SetIcon(Ptr<GuiImageData> icon)
	{
		styleIcon = icon;
	}

	INativeWindow::WindowSizeState GuiRemoteWindow::GetSizeState()
	{
		return remoteWindowSizingConfig.sizeState;
	}

	void GuiRemoteWindow::Show()
	{
		ShowWithSizeState(true, remoteWindowSizingConfig.sizeState);
	}

	void GuiRemoteWindow::ShowDeactivated()
	{
		ShowWithSizeState(false, remoteWindowSizingConfig.sizeState);
	}

	void GuiRemoteWindow::ShowRestored()
	{
		ShowWithSizeState(true, INativeWindow::Restored);
	}

	void GuiRemoteWindow::ShowMaximized()
	{
		ShowWithSizeState(true, INativeWindow::Maximized);
	}

	void GuiRemoteWindow::ShowMinimized()
	{
		ShowWithSizeState(true, INativeWindow::Minimized);
	}

	void GuiRemoteWindow::Hide(bool closeWindow)
	{
		if (!remote->connectionForcedToStop)
		{
			bool cancel = false;
			for (auto l : listeners)
			{
				l->BeforeClosing(cancel);
				if (cancel) return;
			}
			for (auto l : listeners) l->AfterClosing();
		}

		remote->AsyncService()->InvokeInMainThread(this, [this]()
		{
			remote->DestroyNativeWindow(this);
		});
	}

	bool GuiRemoteWindow::IsVisible()
	{
		return statusVisible;
	}

	void GuiRemoteWindow::Enable()
	{
		if (styleEnabled != true)
		{
			styleEnabled = true;
			remoteMessages.RequestWindowNotifySetEnabled(true);
			for (auto l : listeners) l->Enabled();
		}
	}

	void GuiRemoteWindow::Disable()
	{
		if (styleEnabled != false)
		{
			styleEnabled = false;
			remoteMessages.RequestWindowNotifySetEnabled(false);
			for (auto l : listeners) l->Disabled();
		}
	}

	bool GuiRemoteWindow::IsEnabled()
	{
		return styleEnabled;
	}

	void GuiRemoteWindow::SetActivate()
	{
		if (statusActivated != true)
		{
			SetActivated(true);
			remoteMessages.RequestWindowNotifyActivate();
		}
	}

	bool GuiRemoteWindow::IsActivated()
	{
		return statusActivated;
	}

	bool GuiRemoteWindow::IsRenderingAsActivated()
	{
		return statusActivated;
	}

	void GuiRemoteWindow::ShowInTaskBar()
	{
		SET_REMOTE_WINDOW_STYLE(ShowInTaskBar, true);
	}

	void GuiRemoteWindow::HideInTaskBar()
	{
		SET_REMOTE_WINDOW_STYLE(ShowInTaskBar, false);
	}

	bool GuiRemoteWindow::IsAppearedInTaskBar()
	{
		return styleShowInTaskBar;
	}

	void GuiRemoteWindow::EnableActivate()
	{
		CHECK_FAIL(L"vl::presentation::GuiRemoteWindow::EnableActivate()#GuiHostedController is not supposed to call this.");
	}

	void GuiRemoteWindow::DisableActivate()
	{
		CHECK_FAIL(L"vl::presentation::GuiRemoteWindow::EnableActivate()#GuiHostedController is not supposed to call this.");
	}

	bool GuiRemoteWindow::IsEnabledActivate()
	{
		return true;
	}

	bool GuiRemoteWindow::RequireCapture()
	{
		if (!statusCapturing)
		{
			statusCapturing = true;
			remoteMessages.RequestIORequireCapture();
			bool disconnected = false;
			remoteMessages.Submit(disconnected);
			// there is no result from this request, assuming succeeded
		}
		return true;
	}

	bool GuiRemoteWindow::ReleaseCapture()
	{
		if (statusCapturing)
		{
			statusCapturing = false;
			remoteMessages.RequestIOReleaseCapture();
			bool disconnected = false;
			remoteMessages.Submit(disconnected);
			// there is no result from this request, assuming succeeded
		}
		return true;
	}

	bool GuiRemoteWindow::IsCapturing()
	{
		return statusCapturing;
	}

	bool GuiRemoteWindow::GetMaximizedBox()
	{
		return styleMaximizedBox;
	}

	void GuiRemoteWindow::SetMaximizedBox(bool visible)
	{
		SET_REMOTE_WINDOW_STYLE_INVALIDATE(MaximizedBox, visible);
	}

	bool GuiRemoteWindow::GetMinimizedBox()
	{
		return styleMinimizedBox;
	}

	void GuiRemoteWindow::SetMinimizedBox(bool visible)
	{
		SET_REMOTE_WINDOW_STYLE_INVALIDATE(MinimizedBox, visible);
	}

	bool GuiRemoteWindow::GetBorder()
	{
		return styleBorder;
	}

	void GuiRemoteWindow::SetBorder(bool visible)
	{
		SET_REMOTE_WINDOW_STYLE_INVALIDATE(Border, visible);
	}

	bool GuiRemoteWindow::GetSizeBox()
	{
		return styleSizeBox;
	}

	void GuiRemoteWindow::SetSizeBox(bool visible)
	{
		SET_REMOTE_WINDOW_STYLE_INVALIDATE(SizeBox, visible);
	}

	bool GuiRemoteWindow::GetIconVisible()
	{
		return styleIconVisible;
	}

	void GuiRemoteWindow::SetIconVisible(bool visible)
	{
		SET_REMOTE_WINDOW_STYLE_INVALIDATE(IconVisible, visible);
	}

	bool GuiRemoteWindow::GetTitleBar()
	{
		return styleTitleBar;
	}

	void GuiRemoteWindow::SetTitleBar(bool visible)
	{
		SET_REMOTE_WINDOW_STYLE_INVALIDATE(TitleBar, visible);
	}

	bool GuiRemoteWindow::GetTopMost()
	{
		return styleTopMost;
	}

	void GuiRemoteWindow::SetTopMost(bool topmost)
	{
		SET_REMOTE_WINDOW_STYLE(TopMost, topmost);
	}

	void GuiRemoteWindow::SupressAlt()
	{
	}

	bool GuiRemoteWindow::InstallListener(INativeWindowListener* listener)
	{
		if (listeners.Contains(listener))
		{
			return false;
		}
		else
		{
			listeners.Add(listener);
			return true;
		}
	}

	bool GuiRemoteWindow::UninstallListener(INativeWindowListener* listener)
	{
		if (listeners.Contains(listener))
		{
			listeners.Remove(listener);
			return true;
		}
		else
		{
			return false;
		}
	}

	void GuiRemoteWindow::RedrawContent()
	{
	}

#undef SET_REMOTE_WINDOW_STYLE_INVALIDATE
#undef SET_REMOTE_WINDOW_STYLE
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\PROTOCOL\FRAMEOPERATIONS\GUIREMOTEPROTOCOLSCHEMA_BUILDFRAME.CPP
***********************************************************************/

namespace vl::presentation::remoteprotocol
{
	vint RenderingDomBuilder::GetCurrentBoundary()
	{
		if (domBoundaries.Count() > 0)
		{
			return domBoundaries[domBoundaries.Count() - 1];
		}
		else
		{
			return 0;
		}
	}

	vint RenderingDomBuilder::Push(RenderingResultRef ref)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::RenderingDomBuilder::Push(RenderingResultRef)#"
		CHECK_ERROR(ref, ERROR_MESSAGE_PREFIX L"Cannot push a null dom object.");
		vint index = domStack.Add(ref);
		if (!domCurrent->children) domCurrent->children = Ptr(new RenderingResultRefList);
		domCurrent->children->Add(ref);
		domCurrent = ref;
		return index;
#undef ERROR_MESSAGE_PREFIX
	}

	void RenderingDomBuilder::PopTo(vint index)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::RenderingDomBuilder::PopTo(vint)#"
		if (index == domStack.Count() - 1) return;
		CHECK_ERROR(0 <= index && index < domStack.Count(), ERROR_MESSAGE_PREFIX L"Cannot pop to an invalid position.");
		CHECK_ERROR(index >= GetCurrentBoundary(), ERROR_MESSAGE_PREFIX L"Cannot pop across a boundary.");
		while (domStack.Count() - 1 > index)
		{
			domStack.RemoveAt(domStack.Count() - 1);
		}
		domCurrent = domStack[index];
#undef ERROR_MESSAGE_PREFIX
	}

	void RenderingDomBuilder::Pop()
	{
		PopTo(domStack.Count() - 2);
	}

	void RenderingDomBuilder::PopBoundary()
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::RenderingDomBuilder::PopBoundary()#"
		CHECK_ERROR(domBoundaries.Count() > 0, ERROR_MESSAGE_PREFIX L"Cannot pop a boundary when none is in the stack.");
		auto boundaryIndex = domBoundaries.Count() - 1;
		auto boundary = domBoundaries[boundaryIndex];
		domBoundaries.RemoveAt(boundaryIndex);
		PopTo(boundary - 1);
#undef ERROR_MESSAGE_PREFIX
	}


	template<typename TCallback>
	void RenderingDomBuilder::PrepareParentFromCommand(Rect commandBounds, Rect commandValidArea, vint newDomId, TCallback&& calculateValidAreaFromDom)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::RenderingDomBuilder::PrepareParentFromCommand(Rect, Rect, vint, auto&&)#"
		vint min = GetCurrentBoundary();
		bool found = false;
		if (commandValidArea.Contains(commandBounds))
		{
			// if the command is not clipped
			for (vint i = domStack.Count() - 1; i >= min; i--)
			{
				if (domStack[i]->content.validArea.Contains(commandBounds) || i == 0)
				{
					// find the deepest node that could contain the command
					PopTo(i);
					found = true;
					break;
				}
			}
		}
		else
		{
			// otherwise, a parent node causing such clipping should be found or created
			for (vint i = domStack.Count() - 1; i >= min; i--)
			{
				auto domValidArea = calculateValidAreaFromDom(domStack[i]);
				if (domValidArea == commandValidArea)
				{
					// if there is a node who clips command's bound to its valid area
					// that is the parent node of the command
					PopTo(i);
					found = true;
					break;
				}
				else if (domValidArea.Contains(commandValidArea) || i == 0)
				{
					// otherwise find a deepest node who could visually contain the command
					// create a virtual node to satisfy the clipper
					PopTo(i);
					auto parent = Ptr(new RenderingDom);
					parent->id = newDomId;
					parent->content.bounds = commandValidArea;
					parent->content.validArea = commandValidArea;
					Push(parent);
					found = true;
					break;
				}
			}
		}

		// if the new boundary could not fit in the current boundary
		// there must be something wrong
		CHECK_ERROR(found, ERROR_MESSAGE_PREFIX L"Incorrect valid area of dom.");
#undef ERROR_MESSAGE_PREFIX
	}

	void RenderingDomBuilder::RequestRendererBeginRendering()
	{
		domStack.Clear();
		domBoundaries.Clear();
		domRoot = Ptr(new RenderingDom);
		domRoot->id = -1;
		domCurrent = domRoot;
		domStack.Add(domRoot);
	}

	void RenderingDomBuilder::RequestRendererBeginBoundary(const remoteprotocol::ElementBoundary& arguments)
	{
		// a new boundary should be a new node covering existing nodes
		// the valid area of boundary is clipped by its bounds
		// so the valid area to compare from its potential parent dom needs to clipped by its bounds
		PrepareParentFromCommand(
			arguments.bounds,
			arguments.areaClippedBySelf,
			(arguments.id << 2) + 3,
			[&](auto&& dom) { return dom->content.validArea.Intersect(arguments.bounds); }
			);

		auto dom = Ptr(new RenderingDom);
		dom->id = (arguments.id << 2) + 2;
		dom->content.hitTestResult = arguments.hitTestResult;
		dom->content.cursor = arguments.cursor;
		dom->content.bounds = arguments.bounds;
		dom->content.validArea = arguments.areaClippedBySelf;
		domBoundaries.Add(Push(dom));
	}

	void RenderingDomBuilder::RequestRendererEndBoundary()
	{
		PopBoundary();
	}

	void RenderingDomBuilder::RequestRendererRenderElement(const remoteprotocol::ElementRendering& arguments)
	{
		// a new element should be a new node covering existing nodes
		// the valid area of boundary is clipped by its parent
		// so the valid area to compare from its potential parent dom is its valid area
		PrepareParentFromCommand(
			arguments.bounds,
			arguments.areaClippedByParent,
			(arguments.id << 2) + 1,
			[&](auto&& dom) { return dom->content.validArea; }
			);

		auto dom = Ptr(new RenderingDom);
		dom->id = (arguments.id << 2) + 0;
		dom->content.element = arguments.id;
		dom->content.bounds = arguments.bounds;
		dom->content.validArea = arguments.bounds.Intersect(arguments.areaClippedByParent);
		Push(dom);
	}

	Ptr<RenderingDom> RenderingDomBuilder::RequestRendererEndRendering()
	{
		return domRoot;
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\PROTOCOL\FRAMEOPERATIONS\GUIREMOTEPROTOCOLSCHEMA_COPYDOM.CPP
***********************************************************************/

namespace vl::presentation::remoteprotocol
{
	using namespace collections;

	Ptr<RenderingDom> CopyDom(Ptr<RenderingDom> root)
	{
		auto newRoot = Ptr(new RenderingDom);
		newRoot->id = root->id;
		newRoot->content = root->content;
		if (root->children)
		{
			newRoot->children = Ptr(new List<Ptr<RenderingDom>>);
			for (auto child : *root->children.Obj())
			{
				newRoot->children->Add(CopyDom(child));
			}
		}
		return newRoot;
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\PROTOCOL\FRAMEOPERATIONS\GUIREMOTEPROTOCOLSCHEMA_DIFFFRAME.CPP
***********************************************************************/

namespace vl::presentation::remoteprotocol
{
	using namespace collections;

	vint CountDomIndex(Ptr<RenderingDom> root)
	{
		vint counter = 1;
		if (root->children)
		{
			for (auto child : *root->children.Obj())
			{
				counter += CountDomIndex(child);
			} 
		}
		return counter;
	}

	void BuildDomIndexInternal(Ptr<RenderingDom> dom, vint parentId, DomIndex& index, vint& writing)
	{
		index[writing++] = { dom->id,parentId,dom };
		if (dom->children)
		{
			for (auto child : *dom->children.Obj())
			{
				BuildDomIndexInternal(child, dom->id, index, writing);
			}
		}
	}

	void SortDomIndex(DomIndex& index)
	{
		if (index.Count() > 0)
		{
			SortLambda(&index[0], index.Count(), [](const DomIndexItem& a, const DomIndexItem& b)
			{
				return a.id <=> b.id;
			});
		}
	}

	void BuildDomIndex(Ptr<RenderingDom> root, DomIndex& index)
	{
		vint count = CountDomIndex(root);
		vint writing = 0;
		index.Resize(count);
		if (count > 0)
		{
			BuildDomIndexInternal(root, -1, index, writing);
			SortDomIndex(index);
		}
	}

	void UpdateDomInplace(Ptr<RenderingDom> root, DomIndex& index, const RenderingDom_DiffsInOrder& diffs)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::UpdateDomInplace(Ptr<RenderingDom>, DomIndex&, const RenderingDom_DiffsInOrder&)#"
		CHECK_ERROR(root && root->id == -1, ERROR_MESSAGE_PREFIX L"Roots of a DOM must have ID -1.");

		vint createdCount = 0;

		// creating
		{
			vint readingFrom = 0;
			vint readingTo = 0;

			auto markCreated = [&]()
			{
				auto&& to = diffs.diffsInOrder->Get(readingTo++);
				CHECK_ERROR(to.diffType == RenderingDom_DiffType::Created, ERROR_MESSAGE_PREFIX L"Diff of unexisting node must have diffType == Created.");
				createdCount++;
			};

			while (diffs.diffsInOrder && readingTo < diffs.diffsInOrder->Count())
			{
				if (readingFrom < index.Count())
				{
					auto&& from = index[readingFrom];
					auto&& to = diffs.diffsInOrder->Get(readingTo);
					if (from.id < to.id)
					{
						// Nothing happened to this DOM node
						readingFrom++;
					}
					else if (from.id > to.id)
					{
						markCreated();
					}
					else
					{
						// Modified will be delayed and processed together with Created 
						readingFrom++;
						readingTo++;
						CHECK_ERROR(to.diffType != RenderingDom_DiffType::Created, ERROR_MESSAGE_PREFIX L"Diff of existing node must have diffType != Created.");
					}
				}
				else
				{
					markCreated();
				}
			}
		}

		{
			vint writing = index.Count();
			index.Resize(index.Count() + createdCount);
			if (diffs.diffsInOrder)
			{

				for (auto&& to : *diffs.diffsInOrder.Obj())
				{
					if (to.diffType == RenderingDom_DiffType::Created)
					{
						// parentId will be filled later
						auto dom = Ptr(new RenderingDom);
						dom->id = to.id;
						index[writing++] = { to.id,-1,dom };
					}
				}
			}
			SortDomIndex(index);
		}

		// modifying
		{
			vint readingFrom = 0;
			vint readingTo = 0;

			while (readingFrom < index.Count() && (diffs.diffsInOrder && readingTo < diffs.diffsInOrder->Count()))
			{
				bool hasFrom = readingFrom < index.Count();
				bool hasTo = diffs.diffsInOrder && readingTo < diffs.diffsInOrder->Count();

				auto&& from = index[readingFrom];
				auto&& to = diffs.diffsInOrder->Get(readingTo);
				if (from.id < to.id)
				{
					readingFrom++;
				}
				else if (from.id > to.id)
				{
					readingTo++;
				}
				else
				{
					readingFrom++;
					readingTo++;

					if (to.diffType != RenderingDom_DiffType::Deleted)
					{
						if (to.content)
						{
							from.dom->content = to.content.Value();
						}

						if (to.children)
						{
							if (to.children->Count() == 0)
							{
								from.dom->children = nullptr;
							}
							else
							{
								from.dom->children = Ptr(new List<Ptr<RenderingDom>>);
								for (vint childId : *to.children.Obj())
								{
									vint indexToInsert = 0;
									vint indexOfChild = BinarySearchLambda(
										&index[0],
										index.Count(),
										childId,
										indexToInsert,
										[](const DomIndexItem& item, vint id) { return item.id <=> id; }
										);
									CHECK_ERROR(indexOfChild != -1, ERROR_MESSAGE_PREFIX L"Unknown DOM id in diff.");

									index[indexOfChild].parentId = from.id;
									from.dom->children->Add(index[indexOfChild].dom);
								}
							}
						}
					}
				}
			}
		}

		// deleting
		{
			vint readingFrom = 0;
			vint readingTo = 0;
			List<vint> deleteIndices;

			while (diffs.diffsInOrder && readingTo < diffs.diffsInOrder->Count())
			{
				if (readingFrom < index.Count())
				{
					auto&& from = index[readingFrom];
					auto&& to = diffs.diffsInOrder->Get(readingTo);
					if (from.id < to.id)
					{
						readingFrom++;
					}
					else if (from.id > to.id)
					{
						readingTo++;
					}
					else
					{
						if (to.diffType == RenderingDom_DiffType::Deleted)
						{
							deleteIndices.Add(readingFrom);
						}
						readingFrom++;
						readingTo++;
					}
				}
				else
				{
					CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Nodes to be deleted must should appear in the index before modification");
				}
			}

			vint reading = 0;
			vint writing = 0;
			vint testing = 0;

			while (reading < index.Count())
			{
				if (testing < deleteIndices.Count() && deleteIndices[testing] == reading)
				{
					// A node to delete is found, mark and skip
					testing++;
					reading++;
				}
				else
				{
					if (reading != writing)
					{
						// Compact index by removing deleted entries
						index[writing] = index[reading];
					}
					reading++;
					writing++;
				}
			}
			index.Resize(index.Count() - deleteIndices.Count());
		}
#undef ERROR_MESSAGE_PREFIX
	}

	void DiffDom(Ptr<RenderingDom> domFrom, DomIndex& indexFrom, Ptr<RenderingDom> domTo, DomIndex& indexTo, RenderingDom_DiffsInOrder& diffs)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::DiffDom(Ptr<RenderingDom>, DomIndex&, Ptr<RenderingDom>, DomIndex&, RenderingDom_DiffsInOrder&)#"
		CHECK_ERROR(domFrom && domTo && domFrom->id == domTo->id, ERROR_MESSAGE_PREFIX L"Roots of two DOMs tree must have the same ID.");
		diffs.diffsInOrder = Ptr(new List<RenderingDom_Diff>);

		vint readingFrom = 0;
		vint readingTo = 0;

		auto pushDeleted = [&]()
		{
			auto&& dom = indexFrom[readingFrom++].dom;
			RenderingDom_Diff diff;

			diff.id = dom->id;
			diff.diffType = RenderingDom_DiffType::Deleted;
			diffs.diffsInOrder->Add(diff);
		};

		auto pushCreated = [&]()
		{
			auto&& dom = indexTo[readingTo++].dom;
			RenderingDom_Diff diff;
			diff.id = dom->id;
			diff.diffType = RenderingDom_DiffType::Created;

			diff.content = dom->content;
			if (dom->children && dom->children->Count() > 0)
			{
				diff.children = Ptr(new List<vint>);
				CopyFrom(
					*diff.children.Obj(),
					From(*dom->children.Obj())
						.Select([](Ptr<RenderingDom> child) { return child->id; })
					);
			}
			diffs.diffsInOrder->Add(diff);
		};

		auto pushModified = [&]()
		{
			auto&& domFrom = indexFrom[readingFrom++].dom;
			auto&& domTo = indexTo[readingTo++].dom;
			RenderingDom_Diff diff;
			diff.id = domFrom->id;
			diff.diffType = RenderingDom_DiffType::Modified;

			if (
				domFrom->content.hitTestResult != domTo->content.hitTestResult ||
				domFrom->content.cursor != domTo->content.cursor ||
				domFrom->content.element != domTo->content.element ||
				domFrom->content.bounds != domTo->content.bounds ||
				domFrom->content.validArea != domTo->content.validArea
				)
			{
				diff.content = domTo->content;
			}

			bool fromHasChild = domFrom->children && domFrom->children->Count() > 0;
			bool toHasChild = domTo->children && domTo->children->Count() > 0;
			bool childDifferent = false;

			if (fromHasChild != toHasChild)
			{
				childDifferent = true;
			}
			else if (fromHasChild && toHasChild)
			{
				auto fromIds = From(*domFrom->children.Obj())
					.Select([](Ptr<RenderingDom> child) { return child->id; });
				auto toIds = From(*domTo->children.Obj())
					.Select([](Ptr<RenderingDom> child) { return child->id; });
				childDifferent = CompareEnumerable(fromIds, toIds) != 0;
			}

			if (childDifferent)
			{
				diff.children = Ptr(new List<vint>);
				if (toHasChild)
				{
					CopyFrom(
						*diff.children.Obj(),
						From(*domTo->children.Obj())
							.Select([](Ptr<RenderingDom> child) { return child->id; })
						);
				}
			}

			if (diff.content || diff.children)
			{
				diffs.diffsInOrder->Add(diff);
			}
		};

		while (true)
		{
			if (readingFrom < indexFrom.Count() && readingTo < indexTo.Count())
			{
				if (indexFrom[readingFrom].id < indexTo[readingTo].id)
				{
					pushDeleted();
				}
				else if (indexFrom[readingFrom].id > indexTo[readingTo].id)
				{
					pushCreated();
				}
				else
				{
					pushModified();
				}
			}
			else if (readingFrom < indexFrom.Count())
			{
				pushDeleted();
			}
			else if (readingTo < indexTo.Count())
			{
				pushCreated();
			}
			else
			{
				break;
			}
		}

#undef ERROR_MESSAGE_PREFIX
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\REMOTE\PROTOCOL\GENERATED\GUIREMOTEPROTOCOLSCHEMA.CPP
***********************************************************************/
/***********************************************************************
This file is generated by : Vczh GacUI Remote Protocol Generator
Licensed under https ://github.com/vczh-libraries/License
***********************************************************************/


namespace vl::presentation::remoteprotocol
{
	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::CharacterEncoding>(const ::vl::presentation::remoteprotocol::CharacterEncoding & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::CharacterEncoding>(const ::vl::presentation::remoteprotocol::CharacterEncoding&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::remoteprotocol::CharacterEncoding::UTF8: node->content.value = WString::Unmanaged(L"UTF8"); break;
		case ::vl::presentation::remoteprotocol::CharacterEncoding::UTF16: node->content.value = WString::Unmanaged(L"UTF16"); break;
		case ::vl::presentation::remoteprotocol::CharacterEncoding::UTF32: node->content.value = WString::Unmanaged(L"UTF32"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::INativeWindowListener::HitTestResult>(const ::vl::presentation::INativeWindowListener::HitTestResult & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::INativeWindowListener::HitTestResult>(const ::vl::presentation::INativeWindowListener::HitTestResult&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::INativeWindowListener::BorderNoSizing: node->content.value = WString::Unmanaged(L"BorderNoSizing"); break;
		case ::vl::presentation::INativeWindowListener::BorderLeft: node->content.value = WString::Unmanaged(L"BorderLeft"); break;
		case ::vl::presentation::INativeWindowListener::BorderRight: node->content.value = WString::Unmanaged(L"BorderRight"); break;
		case ::vl::presentation::INativeWindowListener::BorderTop: node->content.value = WString::Unmanaged(L"BorderTop"); break;
		case ::vl::presentation::INativeWindowListener::BorderBottom: node->content.value = WString::Unmanaged(L"BorderBottom"); break;
		case ::vl::presentation::INativeWindowListener::BorderLeftTop: node->content.value = WString::Unmanaged(L"BorderLeftTop"); break;
		case ::vl::presentation::INativeWindowListener::BorderRightTop: node->content.value = WString::Unmanaged(L"BorderRightTop"); break;
		case ::vl::presentation::INativeWindowListener::BorderLeftBottom: node->content.value = WString::Unmanaged(L"BorderLeftBottom"); break;
		case ::vl::presentation::INativeWindowListener::BorderRightBottom: node->content.value = WString::Unmanaged(L"BorderRightBottom"); break;
		case ::vl::presentation::INativeWindowListener::Title: node->content.value = WString::Unmanaged(L"Title"); break;
		case ::vl::presentation::INativeWindowListener::ButtonMinimum: node->content.value = WString::Unmanaged(L"ButtonMinimum"); break;
		case ::vl::presentation::INativeWindowListener::ButtonMaximum: node->content.value = WString::Unmanaged(L"ButtonMaximum"); break;
		case ::vl::presentation::INativeWindowListener::ButtonClose: node->content.value = WString::Unmanaged(L"ButtonClose"); break;
		case ::vl::presentation::INativeWindowListener::Client: node->content.value = WString::Unmanaged(L"Client"); break;
		case ::vl::presentation::INativeWindowListener::Icon: node->content.value = WString::Unmanaged(L"Icon"); break;
		case ::vl::presentation::INativeWindowListener::NoDecision: node->content.value = WString::Unmanaged(L"NoDecision"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::INativeCursor::SystemCursorType>(const ::vl::presentation::INativeCursor::SystemCursorType & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::INativeCursor::SystemCursorType>(const ::vl::presentation::INativeCursor::SystemCursorType&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::INativeCursor::SmallWaiting: node->content.value = WString::Unmanaged(L"SmallWaiting"); break;
		case ::vl::presentation::INativeCursor::LargeWaiting: node->content.value = WString::Unmanaged(L"LargeWaiting"); break;
		case ::vl::presentation::INativeCursor::Arrow: node->content.value = WString::Unmanaged(L"Arrow"); break;
		case ::vl::presentation::INativeCursor::Cross: node->content.value = WString::Unmanaged(L"Cross"); break;
		case ::vl::presentation::INativeCursor::Hand: node->content.value = WString::Unmanaged(L"Hand"); break;
		case ::vl::presentation::INativeCursor::Help: node->content.value = WString::Unmanaged(L"Help"); break;
		case ::vl::presentation::INativeCursor::IBeam: node->content.value = WString::Unmanaged(L"IBeam"); break;
		case ::vl::presentation::INativeCursor::SizeAll: node->content.value = WString::Unmanaged(L"SizeAll"); break;
		case ::vl::presentation::INativeCursor::SizeNESW: node->content.value = WString::Unmanaged(L"SizeNESW"); break;
		case ::vl::presentation::INativeCursor::SizeNS: node->content.value = WString::Unmanaged(L"SizeNS"); break;
		case ::vl::presentation::INativeCursor::SizeNWSE: node->content.value = WString::Unmanaged(L"SizeNWSE"); break;
		case ::vl::presentation::INativeCursor::SizeWE: node->content.value = WString::Unmanaged(L"SizeWE"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::INativeWindow::WindowSizeState>(const ::vl::presentation::INativeWindow::WindowSizeState & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::INativeWindow::WindowSizeState>(const ::vl::presentation::INativeWindow::WindowSizeState&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::INativeWindow::WindowSizeState::Minimized: node->content.value = WString::Unmanaged(L"Minimized"); break;
		case ::vl::presentation::INativeWindow::WindowSizeState::Restored: node->content.value = WString::Unmanaged(L"Restored"); break;
		case ::vl::presentation::INativeWindow::WindowSizeState::Maximized: node->content.value = WString::Unmanaged(L"Maximized"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::IOMouseButton>(const ::vl::presentation::remoteprotocol::IOMouseButton & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::IOMouseButton>(const ::vl::presentation::remoteprotocol::IOMouseButton&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::remoteprotocol::IOMouseButton::Left: node->content.value = WString::Unmanaged(L"Left"); break;
		case ::vl::presentation::remoteprotocol::IOMouseButton::Middle: node->content.value = WString::Unmanaged(L"Middle"); break;
		case ::vl::presentation::remoteprotocol::IOMouseButton::Right: node->content.value = WString::Unmanaged(L"Right"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::elements::ElementShapeType>(const ::vl::presentation::elements::ElementShapeType & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::elements::ElementShapeType>(const ::vl::presentation::elements::ElementShapeType&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::elements::ElementShapeType::Rectangle: node->content.value = WString::Unmanaged(L"Rectangle"); break;
		case ::vl::presentation::elements::ElementShapeType::Ellipse: node->content.value = WString::Unmanaged(L"Ellipse"); break;
		case ::vl::presentation::elements::ElementShapeType::RoundRect: node->content.value = WString::Unmanaged(L"RoundRect"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::elements::GuiGradientBackgroundElement::Direction>(const ::vl::presentation::elements::GuiGradientBackgroundElement::Direction & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::elements::GuiGradientBackgroundElement::Direction>(const ::vl::presentation::elements::GuiGradientBackgroundElement::Direction&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::elements::GuiGradientBackgroundElement::Horizontal: node->content.value = WString::Unmanaged(L"Horizontal"); break;
		case ::vl::presentation::elements::GuiGradientBackgroundElement::Vertical: node->content.value = WString::Unmanaged(L"Vertical"); break;
		case ::vl::presentation::elements::GuiGradientBackgroundElement::Slash: node->content.value = WString::Unmanaged(L"Slash"); break;
		case ::vl::presentation::elements::GuiGradientBackgroundElement::Backslash: node->content.value = WString::Unmanaged(L"Backslash"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::elements::Gui3DSplitterElement::Direction>(const ::vl::presentation::elements::Gui3DSplitterElement::Direction & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::elements::Gui3DSplitterElement::Direction>(const ::vl::presentation::elements::Gui3DSplitterElement::Direction&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::elements::Gui3DSplitterElement::Horizontal: node->content.value = WString::Unmanaged(L"Horizontal"); break;
		case ::vl::presentation::elements::Gui3DSplitterElement::Vertical: node->content.value = WString::Unmanaged(L"Vertical"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementHorizontalAlignment>(const ::vl::presentation::remoteprotocol::ElementHorizontalAlignment & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementHorizontalAlignment>(const ::vl::presentation::remoteprotocol::ElementHorizontalAlignment&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::remoteprotocol::ElementHorizontalAlignment::Left: node->content.value = WString::Unmanaged(L"Left"); break;
		case ::vl::presentation::remoteprotocol::ElementHorizontalAlignment::Right: node->content.value = WString::Unmanaged(L"Right"); break;
		case ::vl::presentation::remoteprotocol::ElementHorizontalAlignment::Center: node->content.value = WString::Unmanaged(L"Center"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementVerticalAlignment>(const ::vl::presentation::remoteprotocol::ElementVerticalAlignment & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementVerticalAlignment>(const ::vl::presentation::remoteprotocol::ElementVerticalAlignment&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::remoteprotocol::ElementVerticalAlignment::Top: node->content.value = WString::Unmanaged(L"Top"); break;
		case ::vl::presentation::remoteprotocol::ElementVerticalAlignment::Bottom: node->content.value = WString::Unmanaged(L"Bottom"); break;
		case ::vl::presentation::remoteprotocol::ElementVerticalAlignment::Center: node->content.value = WString::Unmanaged(L"Center"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest>(const ::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest>(const ::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest::FontHeight: node->content.value = WString::Unmanaged(L"FontHeight"); break;
		case ::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest::TotalSize: node->content.value = WString::Unmanaged(L"TotalSize"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::INativeImage::FormatType>(const ::vl::presentation::INativeImage::FormatType & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::INativeImage::FormatType>(const ::vl::presentation::INativeImage::FormatType&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::INativeImage::Bmp: node->content.value = WString::Unmanaged(L"Bmp"); break;
		case ::vl::presentation::INativeImage::Gif: node->content.value = WString::Unmanaged(L"Gif"); break;
		case ::vl::presentation::INativeImage::Icon: node->content.value = WString::Unmanaged(L"Icon"); break;
		case ::vl::presentation::INativeImage::Jpeg: node->content.value = WString::Unmanaged(L"Jpeg"); break;
		case ::vl::presentation::INativeImage::Png: node->content.value = WString::Unmanaged(L"Png"); break;
		case ::vl::presentation::INativeImage::Tiff: node->content.value = WString::Unmanaged(L"Tiff"); break;
		case ::vl::presentation::INativeImage::Wmp: node->content.value = WString::Unmanaged(L"Wmp"); break;
		case ::vl::presentation::INativeImage::Unknown: node->content.value = WString::Unmanaged(L"Unknown"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::elements::IGuiGraphicsParagraph::BreakCondition>(const ::vl::presentation::elements::IGuiGraphicsParagraph::BreakCondition & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::elements::IGuiGraphicsParagraph::BreakCondition>(const ::vl::presentation::elements::IGuiGraphicsParagraph::BreakCondition&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::elements::IGuiGraphicsParagraph::StickToPreviousRun: node->content.value = WString::Unmanaged(L"StickToPreviousRun"); break;
		case ::vl::presentation::elements::IGuiGraphicsParagraph::StickToNextRun: node->content.value = WString::Unmanaged(L"StickToNextRun"); break;
		case ::vl::presentation::elements::IGuiGraphicsParagraph::Alone: node->content.value = WString::Unmanaged(L"Alone"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::elements::IGuiGraphicsParagraph::CaretRelativePosition>(const ::vl::presentation::elements::IGuiGraphicsParagraph::CaretRelativePosition & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::elements::IGuiGraphicsParagraph::CaretRelativePosition>(const ::vl::presentation::elements::IGuiGraphicsParagraph::CaretRelativePosition&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::elements::IGuiGraphicsParagraph::CaretFirst: node->content.value = WString::Unmanaged(L"CaretFirst"); break;
		case ::vl::presentation::elements::IGuiGraphicsParagraph::CaretLast: node->content.value = WString::Unmanaged(L"CaretLast"); break;
		case ::vl::presentation::elements::IGuiGraphicsParagraph::CaretLineFirst: node->content.value = WString::Unmanaged(L"CaretLineFirst"); break;
		case ::vl::presentation::elements::IGuiGraphicsParagraph::CaretLineLast: node->content.value = WString::Unmanaged(L"CaretLineLast"); break;
		case ::vl::presentation::elements::IGuiGraphicsParagraph::CaretMoveLeft: node->content.value = WString::Unmanaged(L"CaretMoveLeft"); break;
		case ::vl::presentation::elements::IGuiGraphicsParagraph::CaretMoveRight: node->content.value = WString::Unmanaged(L"CaretMoveRight"); break;
		case ::vl::presentation::elements::IGuiGraphicsParagraph::CaretMoveUp: node->content.value = WString::Unmanaged(L"CaretMoveUp"); break;
		case ::vl::presentation::elements::IGuiGraphicsParagraph::CaretMoveDown: node->content.value = WString::Unmanaged(L"CaretMoveDown"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RendererType>(const ::vl::presentation::remoteprotocol::RendererType & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RendererType>(const ::vl::presentation::remoteprotocol::RendererType&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::remoteprotocol::RendererType::FocusRectangle: node->content.value = WString::Unmanaged(L"FocusRectangle"); break;
		case ::vl::presentation::remoteprotocol::RendererType::Raw: node->content.value = WString::Unmanaged(L"Raw"); break;
		case ::vl::presentation::remoteprotocol::RendererType::SolidBorder: node->content.value = WString::Unmanaged(L"SolidBorder"); break;
		case ::vl::presentation::remoteprotocol::RendererType::SinkBorder: node->content.value = WString::Unmanaged(L"SinkBorder"); break;
		case ::vl::presentation::remoteprotocol::RendererType::SinkSplitter: node->content.value = WString::Unmanaged(L"SinkSplitter"); break;
		case ::vl::presentation::remoteprotocol::RendererType::SolidBackground: node->content.value = WString::Unmanaged(L"SolidBackground"); break;
		case ::vl::presentation::remoteprotocol::RendererType::GradientBackground: node->content.value = WString::Unmanaged(L"GradientBackground"); break;
		case ::vl::presentation::remoteprotocol::RendererType::InnerShadow: node->content.value = WString::Unmanaged(L"InnerShadow"); break;
		case ::vl::presentation::remoteprotocol::RendererType::SolidLabel: node->content.value = WString::Unmanaged(L"SolidLabel"); break;
		case ::vl::presentation::remoteprotocol::RendererType::Polygon: node->content.value = WString::Unmanaged(L"Polygon"); break;
		case ::vl::presentation::remoteprotocol::RendererType::ImageFrame: node->content.value = WString::Unmanaged(L"ImageFrame"); break;
		case ::vl::presentation::remoteprotocol::RendererType::DocumentParagraph: node->content.value = WString::Unmanaged(L"DocumentParagraph"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom_DiffType>(const ::vl::presentation::remoteprotocol::RenderingDom_DiffType & value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom_DiffType>(const ::vl::presentation::remoteprotocol::RenderingDom_DiffType&)#"
		auto node = Ptr(new glr::json::JsonString);
		switch (value)
		{
		case ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Deleted: node->content.value = WString::Unmanaged(L"Deleted"); break;
		case ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Created: node->content.value = WString::Unmanaged(L"Created"); break;
		case ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Modified: node->content.value = WString::Unmanaged(L"Modified"); break;
		default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
		}
		return node;
#undef ERROR_MESSAGE_PREFIX
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::NativeCoordinate>(const ::vl::presentation::NativeCoordinate & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"value", value.value);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::NativePoint>(const ::vl::presentation::NativePoint & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"x", value.x);
		ConvertCustomTypeToJsonField(node, L"y", value.y);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::NativeSize>(const ::vl::presentation::NativeSize & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"x", value.x);
		ConvertCustomTypeToJsonField(node, L"y", value.y);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::NativeRect>(const ::vl::presentation::NativeRect & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"x1", value.x1);
		ConvertCustomTypeToJsonField(node, L"y1", value.y1);
		ConvertCustomTypeToJsonField(node, L"x2", value.x2);
		ConvertCustomTypeToJsonField(node, L"y2", value.y2);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::NativeMargin>(const ::vl::presentation::NativeMargin & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"left", value.left);
		ConvertCustomTypeToJsonField(node, L"top", value.top);
		ConvertCustomTypeToJsonField(node, L"right", value.right);
		ConvertCustomTypeToJsonField(node, L"bottom", value.bottom);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::Point>(const ::vl::presentation::Point & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"x", value.x);
		ConvertCustomTypeToJsonField(node, L"y", value.y);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::Size>(const ::vl::presentation::Size & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"x", value.x);
		ConvertCustomTypeToJsonField(node, L"y", value.y);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::Rect>(const ::vl::presentation::Rect & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"x1", value.x1);
		ConvertCustomTypeToJsonField(node, L"y1", value.y1);
		ConvertCustomTypeToJsonField(node, L"x2", value.x2);
		ConvertCustomTypeToJsonField(node, L"y2", value.y2);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::FontProperties>(const ::vl::presentation::FontProperties & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"fontFamily", value.fontFamily);
		ConvertCustomTypeToJsonField(node, L"size", value.size);
		ConvertCustomTypeToJsonField(node, L"bold", value.bold);
		ConvertCustomTypeToJsonField(node, L"italic", value.italic);
		ConvertCustomTypeToJsonField(node, L"underline", value.underline);
		ConvertCustomTypeToJsonField(node, L"strikeline", value.strikeline);
		ConvertCustomTypeToJsonField(node, L"antialias", value.antialias);
		ConvertCustomTypeToJsonField(node, L"verticalAntialias", value.verticalAntialias);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::FontConfig>(const ::vl::presentation::remoteprotocol::FontConfig & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"defaultFont", value.defaultFont);
		ConvertCustomTypeToJsonField(node, L"supportedFonts", value.supportedFonts);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ScreenConfig>(const ::vl::presentation::remoteprotocol::ScreenConfig & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"bounds", value.bounds);
		ConvertCustomTypeToJsonField(node, L"clientBounds", value.clientBounds);
		ConvertCustomTypeToJsonField(node, L"scalingX", value.scalingX);
		ConvertCustomTypeToJsonField(node, L"scalingY", value.scalingY);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ControllerGlobalConfig>(const ::vl::presentation::remoteprotocol::ControllerGlobalConfig & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"documentCaretFromEncoding", value.documentCaretFromEncoding);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::WindowSizingConfig>(const ::vl::presentation::remoteprotocol::WindowSizingConfig & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"bounds", value.bounds);
		ConvertCustomTypeToJsonField(node, L"clientBounds", value.clientBounds);
		ConvertCustomTypeToJsonField(node, L"sizeState", value.sizeState);
		ConvertCustomTypeToJsonField(node, L"customFramePadding", value.customFramePadding);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::WindowShowing>(const ::vl::presentation::remoteprotocol::WindowShowing & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"activate", value.activate);
		ConvertCustomTypeToJsonField(node, L"sizeState", value.sizeState);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::NativeWindowMouseInfo>(const ::vl::presentation::NativeWindowMouseInfo & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"ctrl", value.ctrl);
		ConvertCustomTypeToJsonField(node, L"shift", value.shift);
		ConvertCustomTypeToJsonField(node, L"left", value.left);
		ConvertCustomTypeToJsonField(node, L"middle", value.middle);
		ConvertCustomTypeToJsonField(node, L"right", value.right);
		ConvertCustomTypeToJsonField(node, L"x", value.x);
		ConvertCustomTypeToJsonField(node, L"y", value.y);
		ConvertCustomTypeToJsonField(node, L"wheel", value.wheel);
		ConvertCustomTypeToJsonField(node, L"nonClient", value.nonClient);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::IOMouseInfoWithButton>(const ::vl::presentation::remoteprotocol::IOMouseInfoWithButton & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"button", value.button);
		ConvertCustomTypeToJsonField(node, L"info", value.info);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::NativeWindowKeyInfo>(const ::vl::presentation::NativeWindowKeyInfo & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"code", value.code);
		ConvertCustomTypeToJsonField(node, L"ctrl", value.ctrl);
		ConvertCustomTypeToJsonField(node, L"shift", value.shift);
		ConvertCustomTypeToJsonField(node, L"alt", value.alt);
		ConvertCustomTypeToJsonField(node, L"capslock", value.capslock);
		ConvertCustomTypeToJsonField(node, L"autoRepeatKeyDown", value.autoRepeatKeyDown);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::NativeWindowCharInfo>(const ::vl::presentation::NativeWindowCharInfo & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"code", value.code);
		ConvertCustomTypeToJsonField(node, L"ctrl", value.ctrl);
		ConvertCustomTypeToJsonField(node, L"shift", value.shift);
		ConvertCustomTypeToJsonField(node, L"alt", value.alt);
		ConvertCustomTypeToJsonField(node, L"capslock", value.capslock);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::GlobalShortcutKey>(const ::vl::presentation::remoteprotocol::GlobalShortcutKey & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"ctrl", value.ctrl);
		ConvertCustomTypeToJsonField(node, L"shift", value.shift);
		ConvertCustomTypeToJsonField(node, L"alt", value.alt);
		ConvertCustomTypeToJsonField(node, L"code", value.code);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::elements::ElementShape>(const ::vl::presentation::elements::ElementShape & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"shapeType", value.shapeType);
		ConvertCustomTypeToJsonField(node, L"radiusX", value.radiusX);
		ConvertCustomTypeToJsonField(node, L"radiusY", value.radiusY);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementDesc_SolidBorder>(const ::vl::presentation::remoteprotocol::ElementDesc_SolidBorder & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"borderColor", value.borderColor);
		ConvertCustomTypeToJsonField(node, L"shape", value.shape);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementDesc_SinkBorder>(const ::vl::presentation::remoteprotocol::ElementDesc_SinkBorder & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"leftTopColor", value.leftTopColor);
		ConvertCustomTypeToJsonField(node, L"rightBottomColor", value.rightBottomColor);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementDesc_SinkSplitter>(const ::vl::presentation::remoteprotocol::ElementDesc_SinkSplitter & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"leftTopColor", value.leftTopColor);
		ConvertCustomTypeToJsonField(node, L"rightBottomColor", value.rightBottomColor);
		ConvertCustomTypeToJsonField(node, L"direction", value.direction);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementDesc_SolidBackground>(const ::vl::presentation::remoteprotocol::ElementDesc_SolidBackground & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"backgroundColor", value.backgroundColor);
		ConvertCustomTypeToJsonField(node, L"shape", value.shape);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementDesc_GradientBackground>(const ::vl::presentation::remoteprotocol::ElementDesc_GradientBackground & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"leftTopColor", value.leftTopColor);
		ConvertCustomTypeToJsonField(node, L"rightBottomColor", value.rightBottomColor);
		ConvertCustomTypeToJsonField(node, L"direction", value.direction);
		ConvertCustomTypeToJsonField(node, L"shape", value.shape);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementDesc_InnerShadow>(const ::vl::presentation::remoteprotocol::ElementDesc_InnerShadow & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"shadowColor", value.shadowColor);
		ConvertCustomTypeToJsonField(node, L"thickness", value.thickness);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementDesc_Polygon>(const ::vl::presentation::remoteprotocol::ElementDesc_Polygon & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"size", value.size);
		ConvertCustomTypeToJsonField(node, L"borderColor", value.borderColor);
		ConvertCustomTypeToJsonField(node, L"backgroundColor", value.backgroundColor);
		ConvertCustomTypeToJsonField(node, L"points", value.points);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementDesc_SolidLabel>(const ::vl::presentation::remoteprotocol::ElementDesc_SolidLabel & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"textColor", value.textColor);
		ConvertCustomTypeToJsonField(node, L"horizontalAlignment", value.horizontalAlignment);
		ConvertCustomTypeToJsonField(node, L"verticalAlignment", value.verticalAlignment);
		ConvertCustomTypeToJsonField(node, L"wrapLine", value.wrapLine);
		ConvertCustomTypeToJsonField(node, L"wrapLineHeightCalculation", value.wrapLineHeightCalculation);
		ConvertCustomTypeToJsonField(node, L"ellipse", value.ellipse);
		ConvertCustomTypeToJsonField(node, L"multiline", value.multiline);
		ConvertCustomTypeToJsonField(node, L"font", value.font);
		ConvertCustomTypeToJsonField(node, L"text", value.text);
		ConvertCustomTypeToJsonField(node, L"measuringRequest", value.measuringRequest);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ImageCreation>(const ::vl::presentation::remoteprotocol::ImageCreation & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"imageData", value.imageData);
		ConvertCustomTypeToJsonField(node, L"imageDataOmitted", value.imageDataOmitted);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ImageFrameMetadata>(const ::vl::presentation::remoteprotocol::ImageFrameMetadata & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"size", value.size);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ImageMetadata>(const ::vl::presentation::remoteprotocol::ImageMetadata & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"format", value.format);
		ConvertCustomTypeToJsonField(node, L"frames", value.frames);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementDesc_ImageFrame>(const ::vl::presentation::remoteprotocol::ElementDesc_ImageFrame & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"imageId", value.imageId);
		ConvertCustomTypeToJsonField(node, L"imageFrame", value.imageFrame);
		ConvertCustomTypeToJsonField(node, L"horizontalAlignment", value.horizontalAlignment);
		ConvertCustomTypeToJsonField(node, L"verticalAlignment", value.verticalAlignment);
		ConvertCustomTypeToJsonField(node, L"stretch", value.stretch);
		ConvertCustomTypeToJsonField(node, L"enabled", value.enabled);
		ConvertCustomTypeToJsonField(node, L"imageCreation", value.imageCreation);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::DocumentTextRunProperty>(const ::vl::presentation::remoteprotocol::DocumentTextRunProperty & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"textColor", value.textColor);
		ConvertCustomTypeToJsonField(node, L"backgroundColor", value.backgroundColor);
		ConvertCustomTypeToJsonField(node, L"fontProperties", value.fontProperties);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::DocumentInlineObjectRunProperty>(const ::vl::presentation::remoteprotocol::DocumentInlineObjectRunProperty & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"size", value.size);
		ConvertCustomTypeToJsonField(node, L"baseline", value.baseline);
		ConvertCustomTypeToJsonField(node, L"breakCondition", value.breakCondition);
		ConvertCustomTypeToJsonField(node, L"backgroundColor", value.backgroundColor);
		ConvertCustomTypeToJsonField(node, L"backgroundElementId", value.backgroundElementId);
		ConvertCustomTypeToJsonField(node, L"callbackId", value.callbackId);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::DocumentRun>(const ::vl::presentation::remoteprotocol::DocumentRun & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"caretBegin", value.caretBegin);
		ConvertCustomTypeToJsonField(node, L"caretEnd", value.caretEnd);
		ConvertCustomTypeToJsonField(node, L"props", value.props);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraph>(const ::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraph & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"text", value.text);
		ConvertCustomTypeToJsonField(node, L"wrapLine", value.wrapLine);
		ConvertCustomTypeToJsonField(node, L"maxWidth", value.maxWidth);
		ConvertCustomTypeToJsonField(node, L"alignment", value.alignment);
		ConvertCustomTypeToJsonField(node, L"runsDiff", value.runsDiff);
		ConvertCustomTypeToJsonField(node, L"createdInlineObjects", value.createdInlineObjects);
		ConvertCustomTypeToJsonField(node, L"removedInlineObjects", value.removedInlineObjects);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::UpdateElement_DocumentParagraphResponse>(const ::vl::presentation::remoteprotocol::UpdateElement_DocumentParagraphResponse & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"documentSize", value.documentSize);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::GetCaretRequest>(const ::vl::presentation::remoteprotocol::GetCaretRequest & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"caret", value.caret);
		ConvertCustomTypeToJsonField(node, L"relativePosition", value.relativePosition);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::GetCaretResponse>(const ::vl::presentation::remoteprotocol::GetCaretResponse & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"newCaret", value.newCaret);
		ConvertCustomTypeToJsonField(node, L"preferFrontSide", value.preferFrontSide);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::GetCaretBoundsRequest>(const ::vl::presentation::remoteprotocol::GetCaretBoundsRequest & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::GetCaretBoundsResponse>(const ::vl::presentation::remoteprotocol::GetCaretBoundsResponse & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"frontSideBounds", value.frontSideBounds);
		ConvertCustomTypeToJsonField(node, L"backSideBounds", value.backSideBounds);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::GetInlineObjectFromPointRequest>(const ::vl::presentation::remoteprotocol::GetInlineObjectFromPointRequest & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"point", value.point);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::GetNearestCaretFromTextPosRequest>(const ::vl::presentation::remoteprotocol::GetNearestCaretFromTextPosRequest & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"textPos", value.textPos);
		ConvertCustomTypeToJsonField(node, L"frontSide", value.frontSide);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::IsValidCaretRequest>(const ::vl::presentation::remoteprotocol::IsValidCaretRequest & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"caret", value.caret);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::OpenCaretRequest>(const ::vl::presentation::remoteprotocol::OpenCaretRequest & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"caret", value.caret);
		ConvertCustomTypeToJsonField(node, L"caretColor", value.caretColor);
		ConvertCustomTypeToJsonField(node, L"frontSide", value.frontSide);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderInlineObjectRequest>(const ::vl::presentation::remoteprotocol::RenderInlineObjectRequest & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"callbackId", value.callbackId);
		ConvertCustomTypeToJsonField(node, L"location", value.location);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RendererCreation>(const ::vl::presentation::remoteprotocol::RendererCreation & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"type", value.type);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementBeginRendering>(const ::vl::presentation::remoteprotocol::ElementBeginRendering & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"frameId", value.frameId);
		ConvertCustomTypeToJsonField(node, L"updatedElements", value.updatedElements);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementRendering>(const ::vl::presentation::remoteprotocol::ElementRendering & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"bounds", value.bounds);
		ConvertCustomTypeToJsonField(node, L"areaClippedByParent", value.areaClippedByParent);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementBoundary>(const ::vl::presentation::remoteprotocol::ElementBoundary & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"hitTestResult", value.hitTestResult);
		ConvertCustomTypeToJsonField(node, L"cursor", value.cursor);
		ConvertCustomTypeToJsonField(node, L"bounds", value.bounds);
		ConvertCustomTypeToJsonField(node, L"areaClippedBySelf", value.areaClippedBySelf);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementMeasuring_FontHeight>(const ::vl::presentation::remoteprotocol::ElementMeasuring_FontHeight & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"fontFamily", value.fontFamily);
		ConvertCustomTypeToJsonField(node, L"fontSize", value.fontSize);
		ConvertCustomTypeToJsonField(node, L"height", value.height);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementMeasuring_ElementMinSize>(const ::vl::presentation::remoteprotocol::ElementMeasuring_ElementMinSize & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"minSize", value.minSize);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementMeasuring_InlineObjectBounds>(const ::vl::presentation::remoteprotocol::ElementMeasuring_InlineObjectBounds & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"elementId", value.elementId);
		ConvertCustomTypeToJsonField(node, L"callbackId", value.callbackId);
		ConvertCustomTypeToJsonField(node, L"bounds", value.bounds);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementMeasurings>(const ::vl::presentation::remoteprotocol::ElementMeasurings & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"fontHeights", value.fontHeights);
		ConvertCustomTypeToJsonField(node, L"minSizes", value.minSizes);
		ConvertCustomTypeToJsonField(node, L"createdImages", value.createdImages);
		ConvertCustomTypeToJsonField(node, L"inlineObjectBounds", value.inlineObjectBounds);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDomContent>(const ::vl::presentation::remoteprotocol::RenderingDomContent & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"hitTestResult", value.hitTestResult);
		ConvertCustomTypeToJsonField(node, L"cursor", value.cursor);
		ConvertCustomTypeToJsonField(node, L"element", value.element);
		ConvertCustomTypeToJsonField(node, L"bounds", value.bounds);
		ConvertCustomTypeToJsonField(node, L"validArea", value.validArea);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom>(const ::vl::presentation::remoteprotocol::RenderingDom & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"content", value.content);
		ConvertCustomTypeToJsonField(node, L"children", value.children);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom_Diff>(const ::vl::presentation::remoteprotocol::RenderingDom_Diff & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"id", value.id);
		ConvertCustomTypeToJsonField(node, L"diffType", value.diffType);
		ConvertCustomTypeToJsonField(node, L"content", value.content);
		ConvertCustomTypeToJsonField(node, L"children", value.children);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder>(const ::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"diffsInOrder", value.diffsInOrder);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraphFull>(const ::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraphFull & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"paragraph", value.paragraph);
		ConvertCustomTypeToJsonField(node, L"caret", value.caret);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::UnitTest_RenderingFrame>(const ::vl::presentation::remoteprotocol::UnitTest_RenderingFrame & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"frameId", value.frameId);
		ConvertCustomTypeToJsonField(node, L"frameName", value.frameName);
		ConvertCustomTypeToJsonField(node, L"windowSize", value.windowSize);
		ConvertCustomTypeToJsonField(node, L"elements", value.elements);
		ConvertCustomTypeToJsonField(node, L"root", value.root);
		return node;
	}

	template<> vl::Ptr<vl::glr::json::JsonNode> ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::UnitTest_RenderingTrace>(const ::vl::presentation::remoteprotocol::UnitTest_RenderingTrace & value)
	{
		auto node = Ptr(new glr::json::JsonObject);
		ConvertCustomTypeToJsonField(node, L"createdElements", value.createdElements);
		ConvertCustomTypeToJsonField(node, L"imageCreations", value.imageCreations);
		ConvertCustomTypeToJsonField(node, L"imageMetadatas", value.imageMetadatas);
		ConvertCustomTypeToJsonField(node, L"frames", value.frames);
		return node;
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::CharacterEncoding>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::CharacterEncoding& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::CharacterEncoding>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::CharacterEncoding&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"UTF8") value = ::vl::presentation::remoteprotocol::CharacterEncoding::UTF8; else
		if (jsonNode->content.value == L"UTF16") value = ::vl::presentation::remoteprotocol::CharacterEncoding::UTF16; else
		if (jsonNode->content.value == L"UTF32") value = ::vl::presentation::remoteprotocol::CharacterEncoding::UTF32; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::INativeWindowListener::HitTestResult>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::INativeWindowListener::HitTestResult& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::INativeWindowListener::HitTestResult>(Ptr<JsonNode>, ::vl::presentation::INativeWindowListener::HitTestResult&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"BorderNoSizing") value = ::vl::presentation::INativeWindowListener::BorderNoSizing; else
		if (jsonNode->content.value == L"BorderLeft") value = ::vl::presentation::INativeWindowListener::BorderLeft; else
		if (jsonNode->content.value == L"BorderRight") value = ::vl::presentation::INativeWindowListener::BorderRight; else
		if (jsonNode->content.value == L"BorderTop") value = ::vl::presentation::INativeWindowListener::BorderTop; else
		if (jsonNode->content.value == L"BorderBottom") value = ::vl::presentation::INativeWindowListener::BorderBottom; else
		if (jsonNode->content.value == L"BorderLeftTop") value = ::vl::presentation::INativeWindowListener::BorderLeftTop; else
		if (jsonNode->content.value == L"BorderRightTop") value = ::vl::presentation::INativeWindowListener::BorderRightTop; else
		if (jsonNode->content.value == L"BorderLeftBottom") value = ::vl::presentation::INativeWindowListener::BorderLeftBottom; else
		if (jsonNode->content.value == L"BorderRightBottom") value = ::vl::presentation::INativeWindowListener::BorderRightBottom; else
		if (jsonNode->content.value == L"Title") value = ::vl::presentation::INativeWindowListener::Title; else
		if (jsonNode->content.value == L"ButtonMinimum") value = ::vl::presentation::INativeWindowListener::ButtonMinimum; else
		if (jsonNode->content.value == L"ButtonMaximum") value = ::vl::presentation::INativeWindowListener::ButtonMaximum; else
		if (jsonNode->content.value == L"ButtonClose") value = ::vl::presentation::INativeWindowListener::ButtonClose; else
		if (jsonNode->content.value == L"Client") value = ::vl::presentation::INativeWindowListener::Client; else
		if (jsonNode->content.value == L"Icon") value = ::vl::presentation::INativeWindowListener::Icon; else
		if (jsonNode->content.value == L"NoDecision") value = ::vl::presentation::INativeWindowListener::NoDecision; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::INativeCursor::SystemCursorType>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::INativeCursor::SystemCursorType& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::INativeCursor::SystemCursorType>(Ptr<JsonNode>, ::vl::presentation::INativeCursor::SystemCursorType&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"SmallWaiting") value = ::vl::presentation::INativeCursor::SmallWaiting; else
		if (jsonNode->content.value == L"LargeWaiting") value = ::vl::presentation::INativeCursor::LargeWaiting; else
		if (jsonNode->content.value == L"Arrow") value = ::vl::presentation::INativeCursor::Arrow; else
		if (jsonNode->content.value == L"Cross") value = ::vl::presentation::INativeCursor::Cross; else
		if (jsonNode->content.value == L"Hand") value = ::vl::presentation::INativeCursor::Hand; else
		if (jsonNode->content.value == L"Help") value = ::vl::presentation::INativeCursor::Help; else
		if (jsonNode->content.value == L"IBeam") value = ::vl::presentation::INativeCursor::IBeam; else
		if (jsonNode->content.value == L"SizeAll") value = ::vl::presentation::INativeCursor::SizeAll; else
		if (jsonNode->content.value == L"SizeNESW") value = ::vl::presentation::INativeCursor::SizeNESW; else
		if (jsonNode->content.value == L"SizeNS") value = ::vl::presentation::INativeCursor::SizeNS; else
		if (jsonNode->content.value == L"SizeNWSE") value = ::vl::presentation::INativeCursor::SizeNWSE; else
		if (jsonNode->content.value == L"SizeWE") value = ::vl::presentation::INativeCursor::SizeWE; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::INativeWindow::WindowSizeState>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::INativeWindow::WindowSizeState& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::INativeWindow::WindowSizeState>(Ptr<JsonNode>, ::vl::presentation::INativeWindow::WindowSizeState&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"Minimized") value = ::vl::presentation::INativeWindow::WindowSizeState::Minimized; else
		if (jsonNode->content.value == L"Restored") value = ::vl::presentation::INativeWindow::WindowSizeState::Restored; else
		if (jsonNode->content.value == L"Maximized") value = ::vl::presentation::INativeWindow::WindowSizeState::Maximized; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::IOMouseButton>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::IOMouseButton& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::IOMouseButton>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::IOMouseButton&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"Left") value = ::vl::presentation::remoteprotocol::IOMouseButton::Left; else
		if (jsonNode->content.value == L"Middle") value = ::vl::presentation::remoteprotocol::IOMouseButton::Middle; else
		if (jsonNode->content.value == L"Right") value = ::vl::presentation::remoteprotocol::IOMouseButton::Right; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::elements::ElementShapeType>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::elements::ElementShapeType& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::elements::ElementShapeType>(Ptr<JsonNode>, ::vl::presentation::elements::ElementShapeType&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"Rectangle") value = ::vl::presentation::elements::ElementShapeType::Rectangle; else
		if (jsonNode->content.value == L"Ellipse") value = ::vl::presentation::elements::ElementShapeType::Ellipse; else
		if (jsonNode->content.value == L"RoundRect") value = ::vl::presentation::elements::ElementShapeType::RoundRect; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::elements::GuiGradientBackgroundElement::Direction>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::elements::GuiGradientBackgroundElement::Direction& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::elements::GuiGradientBackgroundElement::Direction>(Ptr<JsonNode>, ::vl::presentation::elements::GuiGradientBackgroundElement::Direction&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"Horizontal") value = ::vl::presentation::elements::GuiGradientBackgroundElement::Horizontal; else
		if (jsonNode->content.value == L"Vertical") value = ::vl::presentation::elements::GuiGradientBackgroundElement::Vertical; else
		if (jsonNode->content.value == L"Slash") value = ::vl::presentation::elements::GuiGradientBackgroundElement::Slash; else
		if (jsonNode->content.value == L"Backslash") value = ::vl::presentation::elements::GuiGradientBackgroundElement::Backslash; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::elements::Gui3DSplitterElement::Direction>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::elements::Gui3DSplitterElement::Direction& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::elements::Gui3DSplitterElement::Direction>(Ptr<JsonNode>, ::vl::presentation::elements::Gui3DSplitterElement::Direction&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"Horizontal") value = ::vl::presentation::elements::Gui3DSplitterElement::Horizontal; else
		if (jsonNode->content.value == L"Vertical") value = ::vl::presentation::elements::Gui3DSplitterElement::Vertical; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementHorizontalAlignment>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementHorizontalAlignment& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementHorizontalAlignment>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementHorizontalAlignment&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"Left") value = ::vl::presentation::remoteprotocol::ElementHorizontalAlignment::Left; else
		if (jsonNode->content.value == L"Right") value = ::vl::presentation::remoteprotocol::ElementHorizontalAlignment::Right; else
		if (jsonNode->content.value == L"Center") value = ::vl::presentation::remoteprotocol::ElementHorizontalAlignment::Center; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementVerticalAlignment>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementVerticalAlignment& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementVerticalAlignment>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementVerticalAlignment&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"Top") value = ::vl::presentation::remoteprotocol::ElementVerticalAlignment::Top; else
		if (jsonNode->content.value == L"Bottom") value = ::vl::presentation::remoteprotocol::ElementVerticalAlignment::Bottom; else
		if (jsonNode->content.value == L"Center") value = ::vl::presentation::remoteprotocol::ElementVerticalAlignment::Center; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"FontHeight") value = ::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest::FontHeight; else
		if (jsonNode->content.value == L"TotalSize") value = ::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest::TotalSize; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::INativeImage::FormatType>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::INativeImage::FormatType& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::INativeImage::FormatType>(Ptr<JsonNode>, ::vl::presentation::INativeImage::FormatType&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"Bmp") value = ::vl::presentation::INativeImage::Bmp; else
		if (jsonNode->content.value == L"Gif") value = ::vl::presentation::INativeImage::Gif; else
		if (jsonNode->content.value == L"Icon") value = ::vl::presentation::INativeImage::Icon; else
		if (jsonNode->content.value == L"Jpeg") value = ::vl::presentation::INativeImage::Jpeg; else
		if (jsonNode->content.value == L"Png") value = ::vl::presentation::INativeImage::Png; else
		if (jsonNode->content.value == L"Tiff") value = ::vl::presentation::INativeImage::Tiff; else
		if (jsonNode->content.value == L"Wmp") value = ::vl::presentation::INativeImage::Wmp; else
		if (jsonNode->content.value == L"Unknown") value = ::vl::presentation::INativeImage::Unknown; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::elements::IGuiGraphicsParagraph::BreakCondition>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::elements::IGuiGraphicsParagraph::BreakCondition& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::elements::IGuiGraphicsParagraph::BreakCondition>(Ptr<JsonNode>, ::vl::presentation::elements::IGuiGraphicsParagraph::BreakCondition&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"StickToPreviousRun") value = ::vl::presentation::elements::IGuiGraphicsParagraph::StickToPreviousRun; else
		if (jsonNode->content.value == L"StickToNextRun") value = ::vl::presentation::elements::IGuiGraphicsParagraph::StickToNextRun; else
		if (jsonNode->content.value == L"Alone") value = ::vl::presentation::elements::IGuiGraphicsParagraph::Alone; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::elements::IGuiGraphicsParagraph::CaretRelativePosition>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::elements::IGuiGraphicsParagraph::CaretRelativePosition& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::elements::IGuiGraphicsParagraph::CaretRelativePosition>(Ptr<JsonNode>, ::vl::presentation::elements::IGuiGraphicsParagraph::CaretRelativePosition&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"CaretFirst") value = ::vl::presentation::elements::IGuiGraphicsParagraph::CaretFirst; else
		if (jsonNode->content.value == L"CaretLast") value = ::vl::presentation::elements::IGuiGraphicsParagraph::CaretLast; else
		if (jsonNode->content.value == L"CaretLineFirst") value = ::vl::presentation::elements::IGuiGraphicsParagraph::CaretLineFirst; else
		if (jsonNode->content.value == L"CaretLineLast") value = ::vl::presentation::elements::IGuiGraphicsParagraph::CaretLineLast; else
		if (jsonNode->content.value == L"CaretMoveLeft") value = ::vl::presentation::elements::IGuiGraphicsParagraph::CaretMoveLeft; else
		if (jsonNode->content.value == L"CaretMoveRight") value = ::vl::presentation::elements::IGuiGraphicsParagraph::CaretMoveRight; else
		if (jsonNode->content.value == L"CaretMoveUp") value = ::vl::presentation::elements::IGuiGraphicsParagraph::CaretMoveUp; else
		if (jsonNode->content.value == L"CaretMoveDown") value = ::vl::presentation::elements::IGuiGraphicsParagraph::CaretMoveDown; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RendererType>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::RendererType& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RendererType>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::RendererType&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"FocusRectangle") value = ::vl::presentation::remoteprotocol::RendererType::FocusRectangle; else
		if (jsonNode->content.value == L"Raw") value = ::vl::presentation::remoteprotocol::RendererType::Raw; else
		if (jsonNode->content.value == L"SolidBorder") value = ::vl::presentation::remoteprotocol::RendererType::SolidBorder; else
		if (jsonNode->content.value == L"SinkBorder") value = ::vl::presentation::remoteprotocol::RendererType::SinkBorder; else
		if (jsonNode->content.value == L"SinkSplitter") value = ::vl::presentation::remoteprotocol::RendererType::SinkSplitter; else
		if (jsonNode->content.value == L"SolidBackground") value = ::vl::presentation::remoteprotocol::RendererType::SolidBackground; else
		if (jsonNode->content.value == L"GradientBackground") value = ::vl::presentation::remoteprotocol::RendererType::GradientBackground; else
		if (jsonNode->content.value == L"InnerShadow") value = ::vl::presentation::remoteprotocol::RendererType::InnerShadow; else
		if (jsonNode->content.value == L"SolidLabel") value = ::vl::presentation::remoteprotocol::RendererType::SolidLabel; else
		if (jsonNode->content.value == L"Polygon") value = ::vl::presentation::remoteprotocol::RendererType::Polygon; else
		if (jsonNode->content.value == L"ImageFrame") value = ::vl::presentation::remoteprotocol::RendererType::ImageFrame; else
		if (jsonNode->content.value == L"DocumentParagraph") value = ::vl::presentation::remoteprotocol::RendererType::DocumentParagraph; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_DiffType>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::RenderingDom_DiffType& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_DiffType>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::RenderingDom_DiffType&)#"
		auto jsonNode = node.Cast<glr::json::JsonString>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		if (jsonNode->content.value == L"Deleted") value = ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Deleted; else
		if (jsonNode->content.value == L"Created") value = ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Created; else
		if (jsonNode->content.value == L"Modified") value = ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Modified; else
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value.");
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::NativeCoordinate>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::NativeCoordinate& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::NativeCoordinate>(Ptr<JsonNode>, ::vl::presentation::NativeCoordinate&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"value") ConvertJsonToCustomType(field->value, value.value); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::NativePoint>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::NativePoint& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::NativePoint>(Ptr<JsonNode>, ::vl::presentation::NativePoint&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"x") ConvertJsonToCustomType(field->value, value.x); else
			if (field->name.value == L"y") ConvertJsonToCustomType(field->value, value.y); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::NativeSize>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::NativeSize& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::NativeSize>(Ptr<JsonNode>, ::vl::presentation::NativeSize&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"x") ConvertJsonToCustomType(field->value, value.x); else
			if (field->name.value == L"y") ConvertJsonToCustomType(field->value, value.y); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::NativeRect>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::NativeRect& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::NativeRect>(Ptr<JsonNode>, ::vl::presentation::NativeRect&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"x1") ConvertJsonToCustomType(field->value, value.x1); else
			if (field->name.value == L"y1") ConvertJsonToCustomType(field->value, value.y1); else
			if (field->name.value == L"x2") ConvertJsonToCustomType(field->value, value.x2); else
			if (field->name.value == L"y2") ConvertJsonToCustomType(field->value, value.y2); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::NativeMargin>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::NativeMargin& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::NativeMargin>(Ptr<JsonNode>, ::vl::presentation::NativeMargin&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"left") ConvertJsonToCustomType(field->value, value.left); else
			if (field->name.value == L"top") ConvertJsonToCustomType(field->value, value.top); else
			if (field->name.value == L"right") ConvertJsonToCustomType(field->value, value.right); else
			if (field->name.value == L"bottom") ConvertJsonToCustomType(field->value, value.bottom); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::Point>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::Point& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::Point>(Ptr<JsonNode>, ::vl::presentation::Point&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"x") ConvertJsonToCustomType(field->value, value.x); else
			if (field->name.value == L"y") ConvertJsonToCustomType(field->value, value.y); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::Size>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::Size& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::Size>(Ptr<JsonNode>, ::vl::presentation::Size&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"x") ConvertJsonToCustomType(field->value, value.x); else
			if (field->name.value == L"y") ConvertJsonToCustomType(field->value, value.y); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::Rect>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::Rect& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::Rect>(Ptr<JsonNode>, ::vl::presentation::Rect&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"x1") ConvertJsonToCustomType(field->value, value.x1); else
			if (field->name.value == L"y1") ConvertJsonToCustomType(field->value, value.y1); else
			if (field->name.value == L"x2") ConvertJsonToCustomType(field->value, value.x2); else
			if (field->name.value == L"y2") ConvertJsonToCustomType(field->value, value.y2); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::FontProperties>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::FontProperties& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::FontProperties>(Ptr<JsonNode>, ::vl::presentation::FontProperties&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"fontFamily") ConvertJsonToCustomType(field->value, value.fontFamily); else
			if (field->name.value == L"size") ConvertJsonToCustomType(field->value, value.size); else
			if (field->name.value == L"bold") ConvertJsonToCustomType(field->value, value.bold); else
			if (field->name.value == L"italic") ConvertJsonToCustomType(field->value, value.italic); else
			if (field->name.value == L"underline") ConvertJsonToCustomType(field->value, value.underline); else
			if (field->name.value == L"strikeline") ConvertJsonToCustomType(field->value, value.strikeline); else
			if (field->name.value == L"antialias") ConvertJsonToCustomType(field->value, value.antialias); else
			if (field->name.value == L"verticalAntialias") ConvertJsonToCustomType(field->value, value.verticalAntialias); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::FontConfig>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::FontConfig& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::FontConfig>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::FontConfig&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"defaultFont") ConvertJsonToCustomType(field->value, value.defaultFont); else
			if (field->name.value == L"supportedFonts") ConvertJsonToCustomType(field->value, value.supportedFonts); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ScreenConfig>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ScreenConfig& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ScreenConfig>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ScreenConfig&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"bounds") ConvertJsonToCustomType(field->value, value.bounds); else
			if (field->name.value == L"clientBounds") ConvertJsonToCustomType(field->value, value.clientBounds); else
			if (field->name.value == L"scalingX") ConvertJsonToCustomType(field->value, value.scalingX); else
			if (field->name.value == L"scalingY") ConvertJsonToCustomType(field->value, value.scalingY); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ControllerGlobalConfig>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ControllerGlobalConfig& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ControllerGlobalConfig>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ControllerGlobalConfig&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"documentCaretFromEncoding") ConvertJsonToCustomType(field->value, value.documentCaretFromEncoding); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::WindowSizingConfig>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::WindowSizingConfig& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::WindowSizingConfig>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::WindowSizingConfig&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"bounds") ConvertJsonToCustomType(field->value, value.bounds); else
			if (field->name.value == L"clientBounds") ConvertJsonToCustomType(field->value, value.clientBounds); else
			if (field->name.value == L"sizeState") ConvertJsonToCustomType(field->value, value.sizeState); else
			if (field->name.value == L"customFramePadding") ConvertJsonToCustomType(field->value, value.customFramePadding); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::WindowShowing>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::WindowShowing& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::WindowShowing>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::WindowShowing&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"activate") ConvertJsonToCustomType(field->value, value.activate); else
			if (field->name.value == L"sizeState") ConvertJsonToCustomType(field->value, value.sizeState); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::NativeWindowMouseInfo>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::NativeWindowMouseInfo& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::NativeWindowMouseInfo>(Ptr<JsonNode>, ::vl::presentation::NativeWindowMouseInfo&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"ctrl") ConvertJsonToCustomType(field->value, value.ctrl); else
			if (field->name.value == L"shift") ConvertJsonToCustomType(field->value, value.shift); else
			if (field->name.value == L"left") ConvertJsonToCustomType(field->value, value.left); else
			if (field->name.value == L"middle") ConvertJsonToCustomType(field->value, value.middle); else
			if (field->name.value == L"right") ConvertJsonToCustomType(field->value, value.right); else
			if (field->name.value == L"x") ConvertJsonToCustomType(field->value, value.x); else
			if (field->name.value == L"y") ConvertJsonToCustomType(field->value, value.y); else
			if (field->name.value == L"wheel") ConvertJsonToCustomType(field->value, value.wheel); else
			if (field->name.value == L"nonClient") ConvertJsonToCustomType(field->value, value.nonClient); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::IOMouseInfoWithButton>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::IOMouseInfoWithButton& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::IOMouseInfoWithButton>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::IOMouseInfoWithButton&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"button") ConvertJsonToCustomType(field->value, value.button); else
			if (field->name.value == L"info") ConvertJsonToCustomType(field->value, value.info); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::NativeWindowKeyInfo>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::NativeWindowKeyInfo& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::NativeWindowKeyInfo>(Ptr<JsonNode>, ::vl::presentation::NativeWindowKeyInfo&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"code") ConvertJsonToCustomType(field->value, value.code); else
			if (field->name.value == L"ctrl") ConvertJsonToCustomType(field->value, value.ctrl); else
			if (field->name.value == L"shift") ConvertJsonToCustomType(field->value, value.shift); else
			if (field->name.value == L"alt") ConvertJsonToCustomType(field->value, value.alt); else
			if (field->name.value == L"capslock") ConvertJsonToCustomType(field->value, value.capslock); else
			if (field->name.value == L"autoRepeatKeyDown") ConvertJsonToCustomType(field->value, value.autoRepeatKeyDown); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::NativeWindowCharInfo>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::NativeWindowCharInfo& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::NativeWindowCharInfo>(Ptr<JsonNode>, ::vl::presentation::NativeWindowCharInfo&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"code") ConvertJsonToCustomType(field->value, value.code); else
			if (field->name.value == L"ctrl") ConvertJsonToCustomType(field->value, value.ctrl); else
			if (field->name.value == L"shift") ConvertJsonToCustomType(field->value, value.shift); else
			if (field->name.value == L"alt") ConvertJsonToCustomType(field->value, value.alt); else
			if (field->name.value == L"capslock") ConvertJsonToCustomType(field->value, value.capslock); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GlobalShortcutKey>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::GlobalShortcutKey& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GlobalShortcutKey>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::GlobalShortcutKey&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"ctrl") ConvertJsonToCustomType(field->value, value.ctrl); else
			if (field->name.value == L"shift") ConvertJsonToCustomType(field->value, value.shift); else
			if (field->name.value == L"alt") ConvertJsonToCustomType(field->value, value.alt); else
			if (field->name.value == L"code") ConvertJsonToCustomType(field->value, value.code); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::elements::ElementShape>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::elements::ElementShape& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::elements::ElementShape>(Ptr<JsonNode>, ::vl::presentation::elements::ElementShape&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"shapeType") ConvertJsonToCustomType(field->value, value.shapeType); else
			if (field->name.value == L"radiusX") ConvertJsonToCustomType(field->value, value.radiusX); else
			if (field->name.value == L"radiusY") ConvertJsonToCustomType(field->value, value.radiusY); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_SolidBorder>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementDesc_SolidBorder& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_SolidBorder>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementDesc_SolidBorder&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"borderColor") ConvertJsonToCustomType(field->value, value.borderColor); else
			if (field->name.value == L"shape") ConvertJsonToCustomType(field->value, value.shape); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_SinkBorder>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementDesc_SinkBorder& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_SinkBorder>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementDesc_SinkBorder&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"leftTopColor") ConvertJsonToCustomType(field->value, value.leftTopColor); else
			if (field->name.value == L"rightBottomColor") ConvertJsonToCustomType(field->value, value.rightBottomColor); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_SinkSplitter>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementDesc_SinkSplitter& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_SinkSplitter>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementDesc_SinkSplitter&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"leftTopColor") ConvertJsonToCustomType(field->value, value.leftTopColor); else
			if (field->name.value == L"rightBottomColor") ConvertJsonToCustomType(field->value, value.rightBottomColor); else
			if (field->name.value == L"direction") ConvertJsonToCustomType(field->value, value.direction); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_SolidBackground>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementDesc_SolidBackground& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_SolidBackground>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementDesc_SolidBackground&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"backgroundColor") ConvertJsonToCustomType(field->value, value.backgroundColor); else
			if (field->name.value == L"shape") ConvertJsonToCustomType(field->value, value.shape); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_GradientBackground>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementDesc_GradientBackground& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_GradientBackground>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementDesc_GradientBackground&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"leftTopColor") ConvertJsonToCustomType(field->value, value.leftTopColor); else
			if (field->name.value == L"rightBottomColor") ConvertJsonToCustomType(field->value, value.rightBottomColor); else
			if (field->name.value == L"direction") ConvertJsonToCustomType(field->value, value.direction); else
			if (field->name.value == L"shape") ConvertJsonToCustomType(field->value, value.shape); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_InnerShadow>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementDesc_InnerShadow& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_InnerShadow>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementDesc_InnerShadow&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"shadowColor") ConvertJsonToCustomType(field->value, value.shadowColor); else
			if (field->name.value == L"thickness") ConvertJsonToCustomType(field->value, value.thickness); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_Polygon>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementDesc_Polygon& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_Polygon>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementDesc_Polygon&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"size") ConvertJsonToCustomType(field->value, value.size); else
			if (field->name.value == L"borderColor") ConvertJsonToCustomType(field->value, value.borderColor); else
			if (field->name.value == L"backgroundColor") ConvertJsonToCustomType(field->value, value.backgroundColor); else
			if (field->name.value == L"points") ConvertJsonToCustomType(field->value, value.points); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_SolidLabel>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementDesc_SolidLabel& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_SolidLabel>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementDesc_SolidLabel&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"textColor") ConvertJsonToCustomType(field->value, value.textColor); else
			if (field->name.value == L"horizontalAlignment") ConvertJsonToCustomType(field->value, value.horizontalAlignment); else
			if (field->name.value == L"verticalAlignment") ConvertJsonToCustomType(field->value, value.verticalAlignment); else
			if (field->name.value == L"wrapLine") ConvertJsonToCustomType(field->value, value.wrapLine); else
			if (field->name.value == L"wrapLineHeightCalculation") ConvertJsonToCustomType(field->value, value.wrapLineHeightCalculation); else
			if (field->name.value == L"ellipse") ConvertJsonToCustomType(field->value, value.ellipse); else
			if (field->name.value == L"multiline") ConvertJsonToCustomType(field->value, value.multiline); else
			if (field->name.value == L"font") ConvertJsonToCustomType(field->value, value.font); else
			if (field->name.value == L"text") ConvertJsonToCustomType(field->value, value.text); else
			if (field->name.value == L"measuringRequest") ConvertJsonToCustomType(field->value, value.measuringRequest); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ImageCreation>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ImageCreation& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ImageCreation>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ImageCreation&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"imageData") ConvertJsonToCustomType(field->value, value.imageData); else
			if (field->name.value == L"imageDataOmitted") ConvertJsonToCustomType(field->value, value.imageDataOmitted); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ImageFrameMetadata>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ImageFrameMetadata& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ImageFrameMetadata>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ImageFrameMetadata&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"size") ConvertJsonToCustomType(field->value, value.size); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ImageMetadata>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ImageMetadata& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ImageMetadata>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ImageMetadata&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"format") ConvertJsonToCustomType(field->value, value.format); else
			if (field->name.value == L"frames") ConvertJsonToCustomType(field->value, value.frames); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_ImageFrame>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementDesc_ImageFrame& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_ImageFrame>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementDesc_ImageFrame&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"imageId") ConvertJsonToCustomType(field->value, value.imageId); else
			if (field->name.value == L"imageFrame") ConvertJsonToCustomType(field->value, value.imageFrame); else
			if (field->name.value == L"horizontalAlignment") ConvertJsonToCustomType(field->value, value.horizontalAlignment); else
			if (field->name.value == L"verticalAlignment") ConvertJsonToCustomType(field->value, value.verticalAlignment); else
			if (field->name.value == L"stretch") ConvertJsonToCustomType(field->value, value.stretch); else
			if (field->name.value == L"enabled") ConvertJsonToCustomType(field->value, value.enabled); else
			if (field->name.value == L"imageCreation") ConvertJsonToCustomType(field->value, value.imageCreation); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::DocumentTextRunProperty>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::DocumentTextRunProperty& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::DocumentTextRunProperty>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::DocumentTextRunProperty&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"textColor") ConvertJsonToCustomType(field->value, value.textColor); else
			if (field->name.value == L"backgroundColor") ConvertJsonToCustomType(field->value, value.backgroundColor); else
			if (field->name.value == L"fontProperties") ConvertJsonToCustomType(field->value, value.fontProperties); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::DocumentInlineObjectRunProperty>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::DocumentInlineObjectRunProperty& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::DocumentInlineObjectRunProperty>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::DocumentInlineObjectRunProperty&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"size") ConvertJsonToCustomType(field->value, value.size); else
			if (field->name.value == L"baseline") ConvertJsonToCustomType(field->value, value.baseline); else
			if (field->name.value == L"breakCondition") ConvertJsonToCustomType(field->value, value.breakCondition); else
			if (field->name.value == L"backgroundColor") ConvertJsonToCustomType(field->value, value.backgroundColor); else
			if (field->name.value == L"backgroundElementId") ConvertJsonToCustomType(field->value, value.backgroundElementId); else
			if (field->name.value == L"callbackId") ConvertJsonToCustomType(field->value, value.callbackId); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::DocumentRun>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::DocumentRun& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::DocumentRun>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::DocumentRun&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"caretBegin") ConvertJsonToCustomType(field->value, value.caretBegin); else
			if (field->name.value == L"caretEnd") ConvertJsonToCustomType(field->value, value.caretEnd); else
			if (field->name.value == L"props") ConvertJsonToCustomType(field->value, value.props); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraph>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraph& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraph>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraph&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"text") ConvertJsonToCustomType(field->value, value.text); else
			if (field->name.value == L"wrapLine") ConvertJsonToCustomType(field->value, value.wrapLine); else
			if (field->name.value == L"maxWidth") ConvertJsonToCustomType(field->value, value.maxWidth); else
			if (field->name.value == L"alignment") ConvertJsonToCustomType(field->value, value.alignment); else
			if (field->name.value == L"runsDiff") ConvertJsonToCustomType(field->value, value.runsDiff); else
			if (field->name.value == L"createdInlineObjects") ConvertJsonToCustomType(field->value, value.createdInlineObjects); else
			if (field->name.value == L"removedInlineObjects") ConvertJsonToCustomType(field->value, value.removedInlineObjects); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UpdateElement_DocumentParagraphResponse>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::UpdateElement_DocumentParagraphResponse& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UpdateElement_DocumentParagraphResponse>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::UpdateElement_DocumentParagraphResponse&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"documentSize") ConvertJsonToCustomType(field->value, value.documentSize); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetCaretRequest>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::GetCaretRequest& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetCaretRequest>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::GetCaretRequest&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"caret") ConvertJsonToCustomType(field->value, value.caret); else
			if (field->name.value == L"relativePosition") ConvertJsonToCustomType(field->value, value.relativePosition); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetCaretResponse>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::GetCaretResponse& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetCaretResponse>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::GetCaretResponse&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"newCaret") ConvertJsonToCustomType(field->value, value.newCaret); else
			if (field->name.value == L"preferFrontSide") ConvertJsonToCustomType(field->value, value.preferFrontSide); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetCaretBoundsRequest>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::GetCaretBoundsRequest& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetCaretBoundsRequest>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::GetCaretBoundsRequest&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetCaretBoundsResponse>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::GetCaretBoundsResponse& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetCaretBoundsResponse>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::GetCaretBoundsResponse&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"frontSideBounds") ConvertJsonToCustomType(field->value, value.frontSideBounds); else
			if (field->name.value == L"backSideBounds") ConvertJsonToCustomType(field->value, value.backSideBounds); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetInlineObjectFromPointRequest>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::GetInlineObjectFromPointRequest& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetInlineObjectFromPointRequest>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::GetInlineObjectFromPointRequest&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"point") ConvertJsonToCustomType(field->value, value.point); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetNearestCaretFromTextPosRequest>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::GetNearestCaretFromTextPosRequest& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::GetNearestCaretFromTextPosRequest>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::GetNearestCaretFromTextPosRequest&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"textPos") ConvertJsonToCustomType(field->value, value.textPos); else
			if (field->name.value == L"frontSide") ConvertJsonToCustomType(field->value, value.frontSide); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::IsValidCaretRequest>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::IsValidCaretRequest& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::IsValidCaretRequest>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::IsValidCaretRequest&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"caret") ConvertJsonToCustomType(field->value, value.caret); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::OpenCaretRequest>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::OpenCaretRequest& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::OpenCaretRequest>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::OpenCaretRequest&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"caret") ConvertJsonToCustomType(field->value, value.caret); else
			if (field->name.value == L"caretColor") ConvertJsonToCustomType(field->value, value.caretColor); else
			if (field->name.value == L"frontSide") ConvertJsonToCustomType(field->value, value.frontSide); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderInlineObjectRequest>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::RenderInlineObjectRequest& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderInlineObjectRequest>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::RenderInlineObjectRequest&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"callbackId") ConvertJsonToCustomType(field->value, value.callbackId); else
			if (field->name.value == L"location") ConvertJsonToCustomType(field->value, value.location); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RendererCreation>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::RendererCreation& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RendererCreation>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::RendererCreation&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"type") ConvertJsonToCustomType(field->value, value.type); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementBeginRendering>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementBeginRendering& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementBeginRendering>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementBeginRendering&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"frameId") ConvertJsonToCustomType(field->value, value.frameId); else
			if (field->name.value == L"updatedElements") ConvertJsonToCustomType(field->value, value.updatedElements); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementRendering>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementRendering& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementRendering>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementRendering&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"bounds") ConvertJsonToCustomType(field->value, value.bounds); else
			if (field->name.value == L"areaClippedByParent") ConvertJsonToCustomType(field->value, value.areaClippedByParent); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementBoundary>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementBoundary& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementBoundary>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementBoundary&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"hitTestResult") ConvertJsonToCustomType(field->value, value.hitTestResult); else
			if (field->name.value == L"cursor") ConvertJsonToCustomType(field->value, value.cursor); else
			if (field->name.value == L"bounds") ConvertJsonToCustomType(field->value, value.bounds); else
			if (field->name.value == L"areaClippedBySelf") ConvertJsonToCustomType(field->value, value.areaClippedBySelf); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementMeasuring_FontHeight>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementMeasuring_FontHeight& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementMeasuring_FontHeight>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementMeasuring_FontHeight&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"fontFamily") ConvertJsonToCustomType(field->value, value.fontFamily); else
			if (field->name.value == L"fontSize") ConvertJsonToCustomType(field->value, value.fontSize); else
			if (field->name.value == L"height") ConvertJsonToCustomType(field->value, value.height); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementMeasuring_ElementMinSize>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementMeasuring_ElementMinSize& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementMeasuring_ElementMinSize>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementMeasuring_ElementMinSize&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"minSize") ConvertJsonToCustomType(field->value, value.minSize); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementMeasuring_InlineObjectBounds>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementMeasuring_InlineObjectBounds& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementMeasuring_InlineObjectBounds>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementMeasuring_InlineObjectBounds&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"elementId") ConvertJsonToCustomType(field->value, value.elementId); else
			if (field->name.value == L"callbackId") ConvertJsonToCustomType(field->value, value.callbackId); else
			if (field->name.value == L"bounds") ConvertJsonToCustomType(field->value, value.bounds); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementMeasurings>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementMeasurings& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementMeasurings>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementMeasurings&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"fontHeights") ConvertJsonToCustomType(field->value, value.fontHeights); else
			if (field->name.value == L"minSizes") ConvertJsonToCustomType(field->value, value.minSizes); else
			if (field->name.value == L"createdImages") ConvertJsonToCustomType(field->value, value.createdImages); else
			if (field->name.value == L"inlineObjectBounds") ConvertJsonToCustomType(field->value, value.inlineObjectBounds); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDomContent>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::RenderingDomContent& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDomContent>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::RenderingDomContent&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"hitTestResult") ConvertJsonToCustomType(field->value, value.hitTestResult); else
			if (field->name.value == L"cursor") ConvertJsonToCustomType(field->value, value.cursor); else
			if (field->name.value == L"element") ConvertJsonToCustomType(field->value, value.element); else
			if (field->name.value == L"bounds") ConvertJsonToCustomType(field->value, value.bounds); else
			if (field->name.value == L"validArea") ConvertJsonToCustomType(field->value, value.validArea); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::RenderingDom& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::RenderingDom&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"content") ConvertJsonToCustomType(field->value, value.content); else
			if (field->name.value == L"children") ConvertJsonToCustomType(field->value, value.children); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_Diff>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::RenderingDom_Diff& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_Diff>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::RenderingDom_Diff&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else
			if (field->name.value == L"diffType") ConvertJsonToCustomType(field->value, value.diffType); else
			if (field->name.value == L"content") ConvertJsonToCustomType(field->value, value.content); else
			if (field->name.value == L"children") ConvertJsonToCustomType(field->value, value.children); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"diffsInOrder") ConvertJsonToCustomType(field->value, value.diffsInOrder); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraphFull>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraphFull& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraphFull>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::ElementDesc_DocumentParagraphFull&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"paragraph") ConvertJsonToCustomType(field->value, value.paragraph); else
			if (field->name.value == L"caret") ConvertJsonToCustomType(field->value, value.caret); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UnitTest_RenderingFrame>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::UnitTest_RenderingFrame& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UnitTest_RenderingFrame>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::UnitTest_RenderingFrame&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"frameId") ConvertJsonToCustomType(field->value, value.frameId); else
			if (field->name.value == L"frameName") ConvertJsonToCustomType(field->value, value.frameName); else
			if (field->name.value == L"windowSize") ConvertJsonToCustomType(field->value, value.windowSize); else
			if (field->name.value == L"elements") ConvertJsonToCustomType(field->value, value.elements); else
			if (field->name.value == L"root") ConvertJsonToCustomType(field->value, value.root); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

	template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UnitTest_RenderingTrace>(vl::Ptr<vl::glr::json::JsonNode> node, ::vl::presentation::remoteprotocol::UnitTest_RenderingTrace& value)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UnitTest_RenderingTrace>(Ptr<JsonNode>, ::vl::presentation::remoteprotocol::UnitTest_RenderingTrace&)#"
		auto jsonNode = node.Cast<glr::json::JsonObject>();
		CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type.");
		for (auto field : jsonNode->fields)
		{
			if (field->name.value == L"createdElements") ConvertJsonToCustomType(field->value, value.createdElements); else
			if (field->name.value == L"imageCreations") ConvertJsonToCustomType(field->value, value.imageCreations); else
			if (field->name.value == L"imageMetadatas") ConvertJsonToCustomType(field->value, value.imageMetadatas); else
			if (field->name.value == L"frames") ConvertJsonToCustomType(field->value, value.frames); else
			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member.");
		}
#undef ERROR_MESSAGE_PREFIX
	}

}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE.CPP
***********************************************************************/

namespace vl::presentation::remote_renderer
{
	using namespace elements;
	using namespace remoteprotocol;

	bool GuiRemoteRendererSingle::CanSendEvents()
	{
		return events && !disconnectingFromCore;
	}

	void GuiRemoteRendererSingle::ClearPendingCoreEvents()
	{
		pendingMouseMove.Reset();
		pendingHWheel.Reset();
		pendingVWheel.Reset();
		pendingKeyAutoDown.Reset();
		pendingWindowBoundsUpdate.Reset();
	}

	void GuiRemoteRendererSingle::DisconnectFromCore()
	{
		disconnectingFromCore = true;
		if (window)
		{
			window->ReleaseCapture();
		}
		UnregisterGlobalShortcutKeys();
		ClearPendingCoreEvents();
	}

	void GuiRemoteRendererSingle::RequestCoreForceExitByFatalError()
	{
		if (CanSendEvents())
		{
			events->OnControllerForceExit();
		}
	}

	remoteprotocol::ScreenConfig GuiRemoteRendererSingle::GetScreenConfig(INativeScreen* screen)
	{
		ScreenConfig response;
		response.bounds = screen->GetBounds();
		response.clientBounds = screen->GetClientBounds();
		response.scalingX = screen->GetScalingX();
		response.scalingY = screen->GetScalingY();
		return response;
	}

	remoteprotocol::WindowSizingConfig GuiRemoteRendererSingle::GetWindowSizingConfig()
	{
		WindowSizingConfig response;
		response.bounds = window->GetBounds();
		response.clientBounds = window->GetClientBoundsInScreen();
		response.sizeState = window->GetSizeState();
		response.customFramePadding = window->GetCustomFramePadding();
		return response;
	}

	void GuiRemoteRendererSingle::UpdateConfigsIfNecessary()
	{
		if (!CanSendEvents()) return;
		if (screen)
		{
			auto currentScreen = GetCurrentController()->ScreenService()->GetScreen(window);
			if (screen != currentScreen)
			{
				screen = currentScreen;
				events->OnControllerScreenUpdated(GetScreenConfig(screen));
			}

			auto newWindowSizingConfig = GetWindowSizingConfig();
			if (
				newWindowSizingConfig.bounds != windowSizingConfig.bounds ||
				newWindowSizingConfig.clientBounds != windowSizingConfig.clientBounds)
			{
				windowSizingConfig = newWindowSizingConfig;
				if (!updatingBounds)
				{
					events->OnWindowBoundsUpdated(windowSizingConfig);
				}
			}
			else if (
				newWindowSizingConfig.sizeState != windowSizingConfig.sizeState ||
				newWindowSizingConfig.customFramePadding != windowSizingConfig.customFramePadding)
			{
				windowSizingConfig = newWindowSizingConfig;
				events->OnWindowBoundsUpdated(windowSizingConfig);
			}
		}
	}

	void GuiRemoteRendererSingle::NativeWindowDestroying(INativeWindow* _window)
	{
		if (window == _window)
		{
			window->UninstallListener(this);
			window = nullptr;
		}
	}

	void GuiRemoteRendererSingle::Opened()
	{
		if (!CanSendEvents()) return;
		vl::presentation::remoteprotocol::ControllerGlobalConfig globalConfig;
#if defined VCZH_WCHAR_UTF16
		globalConfig.documentCaretFromEncoding = vl::presentation::remoteprotocol::CharacterEncoding::UTF16;
#elif defined VCZH_WCHAR_UTF32
		globalConfig.documentCaretFromEncoding = vl::presentation::remoteprotocol::CharacterEncoding::UTF32;
#endif
		events->OnControllerConnect(globalConfig);
	}

	void GuiRemoteRendererSingle::BeforeClosing(bool& cancel)
	{
		if (!disconnectingFromCore)
		{
			cancel = true;
			events->OnControllerRequestExit();
		}
	}

	void GuiRemoteRendererSingle::AfterClosing()
	{
		fatalMaskElement = nullptr;
		fatalTextElement = nullptr;
		renderingDom = nullptr;
		focusedParagraphElements.Clear();
		availableElements.Clear();
		availableImages.Clear();
	}

	void GuiRemoteRendererSingle::Closed()
	{
	}

	void GuiRemoteRendererSingle::Moving(NativeRect& bounds, bool fixSizeOnly, bool draggingBorder)
	{
		NativeWindowListener_Moving(window, suggestedMinSize, bounds, fixSizeOnly, draggingBorder);
		if (disconnectingFromCore) return;
		if (draggingBorder)
		{
			auto config = GetWindowSizingConfig();
			auto dx1 = config.clientBounds.x1 - config.bounds.x1;
			auto dy1 = config.clientBounds.y1 - config.bounds.y1;
			auto dx2 = config.clientBounds.x2 - config.bounds.x2;
			auto dy2 = config.clientBounds.y2 - config.bounds.y2;

			config.bounds = bounds;
			config.clientBounds.x1 = config.bounds.x1 + dx1;
			config.clientBounds.y1 = config.bounds.y1 + dy1;
			config.clientBounds.x2 = config.bounds.x2 + dx2;
			config.clientBounds.y2 = config.bounds.y2 + dy2;

			pendingWindowBoundsUpdate = config;
		}
	}

	void GuiRemoteRendererSingle::Moved()
	{
		pendingWindowBoundsUpdate.Reset();
		UpdateConfigsIfNecessary();
	}

	void GuiRemoteRendererSingle::DpiChanged(bool preparing)
	{
		if (preparing)
		{
			UpdateRenderTarget(nullptr);
		}
		else
		{
			GetGuiGraphicsResourceManager()->RecreateRenderTarget(window);
			UpdateRenderTarget(GetGuiGraphicsResourceManager()->GetRenderTarget(window));
			UpdateConfigsIfNecessary();
			if (stoppedByFatalError)
			{
				needRefresh = true;
				ForceRender();
			}
		}
	}

	void GuiRemoteRendererSingle::RenderingAsActivated()
	{
		if (disconnectingFromCore) return;
		events->OnWindowActivatedUpdated(true);
	}

	void GuiRemoteRendererSingle::RenderingAsDeactivated()
	{
		if (disconnectingFromCore) return;
		events->OnWindowActivatedUpdated(false);
	}

	GuiRemoteRendererSingle::GuiRemoteRendererSingle(bool _enabledAutomation)
		: enabledAutomation(_enabledAutomation)
	{
	}

	GuiRemoteRendererSingle::~GuiRemoteRendererSingle()
	{
	}

	void GuiRemoteRendererSingle::RegisterMainWindow(INativeWindow* _window)
	{
		window = _window;
		window->InstallListener(this);
		GetCurrentController()->CallbackService()->InstallListener(this);
	}

	void GuiRemoteRendererSingle::UnregisterMainWindow()
	{
		UnregisterGlobalShortcutKeys();
		GetCurrentController()->CallbackService()->UninstallListener(this);
	}

	bool GuiRemoteRendererSingle::IsDisconnectedFromCore()
	{
		return disconnectingFromCore;
	}

	void GuiRemoteRendererSingle::ForceExitByFatelError()
	{
		if (window)
		{
			DisconnectFromCore();
			window->Hide(true);
		}
	}

	void GuiRemoteRendererSingle::RetainByFatalError(const WString& errorMessage)
	{
		if (stoppedByFatalError) return;

		DisconnectFromCore();
		stoppedByFatalError = true;
		fatalError = errorMessage;
		supressRefresh = false;

		if (window)
		{
			titleBeforeFatalError = window->GetTitle();
			window->SetTitle(WString::Unmanaged(L"[STOPPED] ") + titleBeforeFatalError);
			needRefresh = true;
			ForceRender();
		}
	}

	WString GuiRemoteRendererSingle::GetExecutablePath()
	{
		CHECK_FAIL(L"This function should not be called!");
	}

	void GuiRemoteRendererSingle::Initialize(IGuiRemoteProtocolEvents* _events)
	{
		events = _events;
	}

	void GuiRemoteRendererSingle::Submit(bool& disconnected)
	{
		CHECK_FAIL(L"This function should not be called!");
	}

	IGuiRemoteEventProcessor* GuiRemoteRendererSingle::GetRemoteEventProcessor()
	{
		return nullptr;
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_CONTROLLER.CPP
***********************************************************************/

namespace vl::presentation::remote_renderer
{
	using namespace collections;
	using namespace remoteprotocol;

	void GuiRemoteRendererSingle::RequestControllerGetFontConfig(vint id)
	{
		if (!CanSendEvents()) return;
		FontConfig response;
		auto rs = GetCurrentController()->ResourceService();
		response.defaultFont = rs->GetDefaultFont();
		response.supportedFonts = Ptr(new List<WString>);
		rs->EnumerateFonts(*response.supportedFonts.Obj());
		events->RespondControllerGetFontConfig(id, response);
	}

	void GuiRemoteRendererSingle::RequestControllerGetScreenConfig(vint id)
	{
		if (!CanSendEvents()) return;
		auto primary = screen ? screen : GetCurrentController()->ScreenService()->GetScreen((vint)0);
		events->RespondControllerGetScreenConfig(id, GetScreenConfig(primary));
	}

	void GuiRemoteRendererSingle::RequestControllerConnectionEstablished()
	{
	}

	void GuiRemoteRendererSingle::RequestControllerConnectionStopped()
	{
		if (window)
		{
			DisconnectFromCore();
			window->Hide(true);
		}
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_IO.CPP
***********************************************************************/

namespace vl::presentation::remote_renderer
{
	using namespace remoteprotocol;

/***********************************************************************
* Rendering (Commands)
***********************************************************************/

	void GuiRemoteRendererSingle::UnregisterGlobalShortcutKeys()
	{
		auto inputService = GetCurrentController()->InputService();
		for (vint id : globalShortcuts.Keys())
		{
			inputService->UnregisterGlobalShortcutKey(id);
		}
		globalShortcuts.Clear();

	}

	void GuiRemoteRendererSingle::GlobalShortcutKeyActivated(vint id)
	{
		if (!CanSendEvents()) return;
		vint index = globalShortcuts.Keys().IndexOf(id);
		if (index != -1)
		{
			events->OnIOGlobalShortcutKey(globalShortcuts.Values()[index].id);
		}
	}

	void GuiRemoteRendererSingle::RequestIOUpdateGlobalShortcutKey(const Ptr<collections::List<remoteprotocol::GlobalShortcutKey>>& arguments)
	{
		if (disconnectingFromCore) return;
		UnregisterGlobalShortcutKeys();
		if (arguments)
		{
			auto inputService = GetCurrentController()->InputService();
			for (auto&& shortcut : *arguments.Obj())
			{
				vint id = inputService->RegisterGlobalShortcutKey(shortcut.ctrl, shortcut.shift, shortcut.alt, shortcut.code);
				if (id != -1)
				{
					globalShortcuts.Add(id, shortcut);
				}
			}
		}
	}

	void GuiRemoteRendererSingle::RequestIORequireCapture()
	{
		if (disconnectingFromCore) return;
		window->RequireCapture();
	}

	void GuiRemoteRendererSingle::RequestIOReleaseCapture()
	{
		if (disconnectingFromCore) return;
		window->ReleaseCapture();
	}

	void GuiRemoteRendererSingle::RequestIOIsKeyPressing(vint id, const VKEY& arguments)
	{
		if (!CanSendEvents()) return;
		bool result = GetCurrentController()->InputService()->IsKeyPressing(arguments);
		events->RespondIOIsKeyPressing(id, result);
	}

	void GuiRemoteRendererSingle::RequestIOIsKeyToggled(vint id, const VKEY& arguments)
	{
		if (!CanSendEvents()) return;
		bool result = GetCurrentController()->InputService()->IsKeyToggled(arguments);
		events->RespondIOIsKeyToggled(id, result);
	}

/***********************************************************************
* Rendering (INativeWindow)
***********************************************************************/

	void GuiRemoteRendererSingle::LeftButtonDown(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		SendAccumulatedMessages();
		IOMouseInfoWithButton arguments;
		arguments.button = IOMouseButton::Left;
		arguments.info = info;
		events->OnIOButtonDown(arguments);
	}

	void GuiRemoteRendererSingle::LeftButtonUp(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		SendAccumulatedMessages();
		IOMouseInfoWithButton arguments;
		arguments.button = IOMouseButton::Left;
		arguments.info = info;
		events->OnIOButtonUp(arguments);
	}

	void GuiRemoteRendererSingle::LeftButtonDoubleClick(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		SendAccumulatedMessages();
		IOMouseInfoWithButton arguments;
		arguments.button = IOMouseButton::Left;
		arguments.info = info;
		events->OnIOButtonDoubleClick(arguments);
	}

	void GuiRemoteRendererSingle::RightButtonDown(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		SendAccumulatedMessages();
		IOMouseInfoWithButton arguments;
		arguments.button = IOMouseButton::Right;
		arguments.info = info;
		events->OnIOButtonDown(arguments);
	}

	void GuiRemoteRendererSingle::RightButtonUp(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		SendAccumulatedMessages();
		IOMouseInfoWithButton arguments;
		arguments.button = IOMouseButton::Right;
		arguments.info = info;
		events->OnIOButtonUp(arguments);
	}

	void GuiRemoteRendererSingle::RightButtonDoubleClick(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		SendAccumulatedMessages();
		IOMouseInfoWithButton arguments;
		arguments.button = IOMouseButton::Right;
		arguments.info = info;
		events->OnIOButtonDoubleClick(arguments);
	}

	void GuiRemoteRendererSingle::MiddleButtonDown(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		SendAccumulatedMessages();
		IOMouseInfoWithButton arguments;
		arguments.button = IOMouseButton::Middle;
		arguments.info = info;
		events->OnIOButtonDown(arguments);
	}

	void GuiRemoteRendererSingle::MiddleButtonUp(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		SendAccumulatedMessages();
		IOMouseInfoWithButton arguments;
		arguments.button = IOMouseButton::Middle;
		arguments.info = info;
		events->OnIOButtonUp(arguments);
	}

	void GuiRemoteRendererSingle::MiddleButtonDoubleClick(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		SendAccumulatedMessages();
		IOMouseInfoWithButton arguments;
		arguments.button = IOMouseButton::Middle;
		arguments.info = info;
		events->OnIOButtonDoubleClick(arguments);
	}

	void GuiRemoteRendererSingle::HorizontalWheel(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		auto copy = info;
		if (pendingHWheel) copy.wheel += pendingHWheel.Value().wheel;
		pendingHWheel = copy;
	}

	void GuiRemoteRendererSingle::VerticalWheel(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		auto copy = info;
		if (pendingVWheel) copy.wheel += pendingVWheel.Value().wheel;
		pendingVWheel = copy;
	}

	void GuiRemoteRendererSingle::MouseMoving(const NativeWindowMouseInfo& info)
	{
		if (!CanSendEvents()) return;
		pendingMouseMove = info;
		if (renderingDom)
		{
			INativeWindowListener::HitTestResult hitTestResult = INativeWindowListener::NoDecision;
			INativeCursor* cursor = nullptr;
			HitTest(renderingDom, window->Convert(NativePoint{ info.x,info.y }), hitTestResult, cursor);
			window->SetWindowCursor(cursor);
		}
	}

	void GuiRemoteRendererSingle::MouseEntered()
	{
		if (!CanSendEvents()) return;
		events->OnIOMouseEntered();
	}

	void GuiRemoteRendererSingle::MouseLeaved()
	{
		if (!CanSendEvents()) return;
		events->OnIOMouseLeaved();
	}

	void GuiRemoteRendererSingle::KeyDown(const NativeWindowKeyInfo& info)
	{
		if (!CanSendEvents()) return;
		if (info.autoRepeatKeyDown)
		{
			pendingKeyAutoDown = info;
		}
		else
		{
			events->OnIOKeyDown(info);
		}
	}

	void GuiRemoteRendererSingle::KeyUp(const NativeWindowKeyInfo& info)
	{
		if (!CanSendEvents()) return;
		pendingKeyAutoDown.Reset();
		if (!info.ctrl && !info.shift && info.code == VKEY::KEY_MENU)
		{
			window->SupressAlt();
		}
		events->OnIOKeyUp(info);
	}

	void GuiRemoteRendererSingle::Char(const NativeWindowCharInfo& info)
	{
		if (!CanSendEvents()) return;
		events->OnIOChar(info);
	}

	void GuiRemoteRendererSingle::SendAccumulatedMessages()
	{
		if (!CanSendEvents())
		{
			ClearPendingCoreEvents();
			return;
		}
		if (pendingMouseMove)
		{
			events->OnIOMouseMoving(pendingMouseMove.Value());
			pendingMouseMove.Reset();
		}
		if (pendingHWheel)
		{
			events->OnIOHWheel(pendingHWheel.Value());
			pendingHWheel.Reset();
		}
		if (pendingVWheel)
		{
			events->OnIOVWheel(pendingVWheel.Value());
			pendingVWheel.Reset();
		}
		if (pendingKeyAutoDown)
		{
			events->OnIOKeyDown(pendingKeyAutoDown.Value());
			pendingKeyAutoDown.Reset();
		}
		if (pendingWindowBoundsUpdate)
		{
			events->OnWindowBoundsUpdated(pendingWindowBoundsUpdate.Value());
			pendingWindowBoundsUpdate.Reset();
		}
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_MAINWINDOW.CPP
***********************************************************************/

namespace vl::presentation::remote_renderer
{
	using namespace remoteprotocol;

	void GuiRemoteRendererSingle::RequestWindowGetBounds(vint id)
	{
		if (!CanSendEvents()) return;
		events->RespondWindowGetBounds(id, GetWindowSizingConfig());
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetBounds(const NativeRect& arguments)
	{
		if (disconnectingFromCore) return;
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestWindowNotifySetBounds(const NativeRect&)#"
		CHECK_ERROR(!updatingBounds, ERROR_MESSAGE_PREFIX L"This function cannot be called recursively.");

		updatingBounds = true;
		if (!screen)
		{
			auto primary = GetCurrentController()->ScreenService()->GetScreen((vint)0);
			NativeRect screenBounds = primary->GetBounds();
			auto x = (screenBounds.Width() - arguments.Width()) / 2;
			auto y = (screenBounds.Height() - arguments.Height()) / 2;
			window->SetBounds({ {x,y},arguments.GetSize() });

			screen = primary;
			windowSizingConfig = GetWindowSizingConfig();
		}
		else
		{
			window->SetBounds(arguments);
		}
		updatingBounds = false;
#undef ERROR_MESSAGE_PREFIX
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetTitle(const WString& arguments)
	{
		if (disconnectingFromCore) return;
		window->SetTitle(arguments);
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetEnabled(const bool& arguments)
	{
		if (disconnectingFromCore) return;
		if (arguments)
		{
			window->Enable();
		}
		else
		{
			window->Disable();
		}
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetTopMost(const bool& arguments)
	{
		if (disconnectingFromCore) return;
		window->SetTopMost(arguments);
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetShowInTaskBar(const bool& arguments)
	{
		if (disconnectingFromCore) return;
		if (arguments)
		{
			window->ShowInTaskBar();
		}
		else
		{
			window->HideInTaskBar();
		}
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetClientSize(const NativeSize& arguments)
	{
		if (disconnectingFromCore) return;
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestWindowNotifySetClientSize(const NativeSize&)#"
		CHECK_ERROR(screen, ERROR_MESSAGE_PREFIX L"This function cannot be called before RequestWindowNotifySetBounds.");

		window->SetClientSize(arguments);
#undef ERROR_MESSAGE_PREFIX
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetCustomFrameMode(const bool& arguments)
	{
		if (disconnectingFromCore) return;
		if (window->IsCustomFrameModeEnabled() != arguments)
		{
			if (arguments)
			{
				window->EnableCustomFrameMode();
			}
			else
			{
				window->DisableCustomFrameMode();
			}
			UpdateConfigsIfNecessary();
		}
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetMaximizedBox(const bool& arguments)
	{
		if (disconnectingFromCore) return;
		window->SetMaximizedBox(arguments);
		UpdateConfigsIfNecessary();
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetMinimizedBox(const bool& arguments)
	{
		if (disconnectingFromCore) return;
		window->SetMinimizedBox(arguments);
		UpdateConfigsIfNecessary();
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetBorder(const bool& arguments)
	{
		if (disconnectingFromCore) return;
		window->SetBorder(arguments);
		UpdateConfigsIfNecessary();
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetSizeBox(const bool& arguments)
	{
		if (disconnectingFromCore) return;
		window->SetSizeBox(arguments);
		UpdateConfigsIfNecessary();
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetIconVisible(const bool& arguments)
	{
		if (disconnectingFromCore) return;
		window->SetIconVisible(arguments);
		UpdateConfigsIfNecessary();
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetTitleBar(const bool& arguments)
	{
		if (disconnectingFromCore) return;
		window->SetTitleBar(arguments);
		UpdateConfigsIfNecessary();
	}

	void GuiRemoteRendererSingle::RequestWindowNotifyActivate()
	{
		if (disconnectingFromCore) return;
		window->SetActivate();
	}

	void GuiRemoteRendererSingle::RequestWindowNotifyShow(const remoteprotocol::WindowShowing& arguments)
	{
		if (disconnectingFromCore) return;
		if (arguments.sizeState != window->GetSizeState())
		{
			if (arguments.activate)
			{
				window->SetActivate();
			}
			switch (arguments.sizeState)
			{
			case INativeWindow::Minimized:
				window->ShowMinimized();
				break;
			case INativeWindow::Restored:
				window->ShowRestored();
				break;
			case INativeWindow::Maximized:
				window->ShowMaximized();
				break;
			}
		}
	}

	void GuiRemoteRendererSingle::RequestWindowNotifyMinSize(const NativeSize& arguments)
	{
		if (disconnectingFromCore) return;
		auto clientSize = window->GetClientSize();
		auto size = window->GetBounds().GetSize();
		suggestedMinSize.x = arguments.x + size.x - clientSize.x;
		suggestedMinSize.y = arguments.y + size.y - clientSize.y;
	}

	void GuiRemoteRendererSingle::RequestWindowNotifySetCaret(const NativePoint& arguments)
	{
		if (disconnectingFromCore) return;
		window->SetCaretPoint(arguments);
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_RENDERING.CPP
***********************************************************************/

namespace vl::presentation::remote_renderer
{
	using namespace collections;
	using namespace elements;
	using namespace remoteprotocol;

	Alignment GuiRemoteRendererSingle::GetAlignment(remoteprotocol::ElementHorizontalAlignment alignment)
	{
		switch (alignment)
		{
		case remoteprotocol::ElementHorizontalAlignment::Left: return Alignment::Left;
		case remoteprotocol::ElementHorizontalAlignment::Right: return Alignment::Right;
		default: return Alignment::Center;
		}
	}

	Alignment GuiRemoteRendererSingle::GetAlignment(remoteprotocol::ElementVerticalAlignment alignment)
	{
		switch (alignment)
		{
		case remoteprotocol::ElementVerticalAlignment::Top: return Alignment::Top;
		case remoteprotocol::ElementVerticalAlignment::Bottom: return Alignment::Bottom;
		default: return Alignment::Center;
		}
	}

/***********************************************************************
* Rendering
***********************************************************************/

	void GuiRemoteRendererSingle::RequestRendererCreated(const Ptr<collections::List<remoteprotocol::RendererCreation>>& arguments)
	{
		if (disconnectingFromCore) return;
		supressRefresh = true;
		if (arguments)
		{
			for (auto&& rc : *arguments.Obj())
			{
				Ptr<IGuiGraphicsElement> element;
				switch (rc.type)
				{
				case RendererType::FocusRectangle:
					element = Ptr(GuiFocusRectangleElement::Create());
					break;
				case RendererType::Raw:
					// Do Nothing
					break;
				case RendererType::SolidBorder:
					element = Ptr(GuiSolidBorderElement::Create());
					break;
				case RendererType::SinkBorder:
					element = Ptr(Gui3DBorderElement::Create());
					break;
				case RendererType::SinkSplitter:
					element = Ptr(Gui3DSplitterElement::Create());
					break;
				case RendererType::SolidBackground:
					element = Ptr(GuiSolidBackgroundElement::Create());
					break;
				case RendererType::GradientBackground:
					element = Ptr(GuiGradientBackgroundElement::Create());
					break;
				case RendererType::InnerShadow:
					element = Ptr(GuiInnerShadowElement::Create());
					break;
				case RendererType::SolidLabel:
					element = Ptr(GuiSolidLabelElement::Create());
					break;
				case RendererType::Polygon:
					element = Ptr(GuiPolygonElement::Create());
					break;
				case RendererType::ImageFrame:
					element = Ptr(GuiImageFrameElement::Create());
					break;
				case RendererType::DocumentParagraph:
					element = CreateRemoteDocumentParagraphElement(rc.id);
					break;
				default:;
				}

				if (element)
				{
					element->GetRenderer()->SetRenderTarget(GetGuiGraphicsResourceManager()->GetRenderTarget(window));

					if (availableElements.Keys().Contains(rc.id))
					{
						availableElements.Set(rc.id, element);
					}
					else
					{
						availableElements.Add(rc.id, element);
					}
				}

				if (enabledAutomation)
				{
					RenderingElement renderingElement;
					renderingElement.key = rc.type;
					renderingElements.Set(rc.id, renderingElement);
				}
			}
		}
	}

	void GuiRemoteRendererSingle::RequestRendererDestroyed(const Ptr<collections::List<vint>>& arguments)
	{
		if (disconnectingFromCore) return;
		supressRefresh = true;
		if (arguments)
		{
			for (auto id : *arguments.Obj())
			{
				focusedParagraphElements.Remove(id);
				availableElements.Remove(id);
				solidLabelMeasurings.Remove(id);

				if (enabledAutomation)
				{
					renderingElements.Remove(id);
				}
			}
		}
	}

	void GuiRemoteRendererSingle::RequestRendererBeginRendering(const remoteprotocol::ElementBeginRendering& arguments)
	{
		if (disconnectingFromCore) return;
		supressRefresh = true;
		if (arguments.updatedElements)
		{
			for (auto&& desc : *arguments.updatedElements.Obj())
			{
				desc.Apply(Overloading(
					[&](const remoteprotocol::ElementDesc_SolidBorder& d) { RequestRendererUpdateElement_SolidBorder(d); },
					[&](const remoteprotocol::ElementDesc_SinkBorder& d) { RequestRendererUpdateElement_SinkBorder(d); },
					[&](const remoteprotocol::ElementDesc_SinkSplitter& d) { RequestRendererUpdateElement_SinkSplitter(d); },
					[&](const remoteprotocol::ElementDesc_SolidBackground& d) { RequestRendererUpdateElement_SolidBackground(d); },
					[&](const remoteprotocol::ElementDesc_GradientBackground& d) { RequestRendererUpdateElement_GradientBackground(d); },
					[&](const remoteprotocol::ElementDesc_InnerShadow& d) { RequestRendererUpdateElement_InnerShadow(d); },
					[&](const remoteprotocol::ElementDesc_Polygon& d) { RequestRendererUpdateElement_Polygon(d); },
					[&](const remoteprotocol::ElementDesc_SolidLabel& d) { RequestRendererUpdateElement_SolidLabel(d); },
					[&](const remoteprotocol::ElementDesc_ImageFrame& d) { RequestRendererUpdateElement_ImageFrame(d); }
				));

				if (enabledAutomation)
				{
					desc.Apply(Overloading(
						[&](const remoteprotocol::ElementDesc_SolidLabel& d)
						{
							vint index = renderingElements.Keys().IndexOf(d.id);
							if (index != -1)
							{
								auto& renderingElement = const_cast<RenderingElement&>(renderingElements.Values()[index]);
								auto copiedDesc = d;
								if (renderingElement.value)
								{
									if (auto solidLabel = renderingElement.value.Value().TryGet<remoteprotocol::ElementDesc_SolidLabel>())
									{
										if (!copiedDesc.font) copiedDesc.font = solidLabel->font;
										if (!copiedDesc.text) copiedDesc.text = solidLabel->text;
										if (!copiedDesc.measuringRequest) copiedDesc.measuringRequest = solidLabel->measuringRequest;
									}
								}
								renderingElement.value = copiedDesc;
							}
						},
						[&](const auto& d)
						{
							vint index = renderingElements.Keys().IndexOf(d.id);
							if (index != -1)
							{
								auto& renderingElement = const_cast<RenderingElement&>(renderingElements.Values()[index]);
								renderingElement.value = d;
							}
						}
					));
				}
			}
		}
	}

	void GuiRemoteRendererSingle::RequestRendererEndRendering(vint id)
	{
		if (!CanSendEvents()) return;
		supressRefresh = false;
		if (needRefresh)
		{
			needRefresh = false;
			ForceRender();
		}
		events->RespondRendererEndRendering(id, elementMeasurings);
		elementMeasurings = {};
		fontHeightMeasurings.Clear();
	}

	void GuiRemoteRendererSingle::RequestRendererIdle()
	{
		// Hint only; intentionally ignored.
	}

/***********************************************************************
* Rendering (Dom)
***********************************************************************/

	void GuiRemoteRendererSingle::RequestRendererRenderDom(const Ptr<remoteprotocol::RenderingDom>& arguments)
	{
		if (disconnectingFromCore) return;
		renderingDom = arguments;
		if (renderingDom)
		{
			BuildDomIndex(renderingDom, renderingDomIndex);
		}
		needRefresh = true;
	}

	void GuiRemoteRendererSingle::RequestRendererRenderDomDiff(const remoteprotocol::RenderingDom_DiffsInOrder& arguments)
	{
		if (disconnectingFromCore) return;
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestRendererRenderDomDiff(const RenderingDom_DiffsInOrder&)#"
		CHECK_ERROR(renderingDom, ERROR_MESSAGE_PREFIX L"This function must be called after RequestRendererRenderDom.");

		UpdateDomInplace(renderingDom, renderingDomIndex, arguments);
		needRefresh = true;
#undef ERROR_MESSAGE_PREFIX
	}

/***********************************************************************
* Rendering (Commands)
***********************************************************************/

	void GuiRemoteRendererSingle::RequestRendererBeginBoundary(const remoteprotocol::ElementBoundary& arguments)
	{
		if (disconnectingFromCore) return;
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestRendererBeginBoundary(const ElementBoundary&)#"
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"The current implementation require dom-diff enabled in core side.");
#undef ERROR_MESSAGE_PREFIX
	}

	void GuiRemoteRendererSingle::RequestRendererEndBoundary()
	{
		if (disconnectingFromCore) return;
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestRendererEndBoundary()#"
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"The current implementation require dom-diff enabled in core side.");
#undef ERROR_MESSAGE_PREFIX
	}

	void GuiRemoteRendererSingle::RequestRendererRenderElement(const remoteprotocol::ElementRendering& arguments)
	{
		if (disconnectingFromCore) return;
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestRendererRenderElement(const ElementRendering&)#"
		CHECK_FAIL(ERROR_MESSAGE_PREFIX L"The current implementation require dom-diff enabled in core side.");
#undef ERROR_MESSAGE_PREFIX
	}

/***********************************************************************
* Rendering (INativeWindow)
***********************************************************************/

	void GuiRemoteRendererSingle::UpdateRenderTarget(elements::IGuiGraphicsRenderTarget* rt)
	{
		for (auto element : availableElements.Values())
		{
			element->GetRenderer()->SetRenderTarget(rt);
		}
		if (fatalMaskElement)
		{
			fatalMaskElement->GetRenderer()->SetRenderTarget(rt);
		}
		if (fatalTextElement)
		{
			fatalTextElement->GetRenderer()->SetRenderTarget(rt);
		}
	}

	void GuiRemoteRendererSingle::EnsureFatalOverlayElements(elements::IGuiGraphicsRenderTarget* rt)
	{
		if (!fatalMaskElement)
		{
			fatalMaskElement = Ptr(GuiSolidBackgroundElement::Create());
			fatalMaskElement->SetColor(Color(255, 255, 255, 128));
		}
		if (!fatalTextElement)
		{
			fatalTextElement = Ptr(GuiSolidLabelElement::Create());
			auto font = GetCurrentController()->ResourceService()->GetDefaultFont();
			if (font.size < 14)
			{
				font.size = 14;
			}
			font.bold = true;
			fatalTextElement->SetFont(font);
			fatalTextElement->SetColor(Color(128, 0, 0));
			fatalTextElement->SetMultiline(true);
			fatalTextElement->SetWrapLine(true);
			fatalTextElement->SetAlignments(Alignment::Center, Alignment::Center);
		}
		fatalMaskElement->GetRenderer()->SetRenderTarget(rt);
		fatalTextElement->GetRenderer()->SetRenderTarget(rt);
	}

	void GuiRemoteRendererSingle::RenderFatalOverlay(elements::IGuiGraphicsRenderTarget* rt)
	{
		if (!stoppedByFatalError || !fatalError) return;

		EnsureFatalOverlayElements(rt);
		fatalTextElement->SetText(fatalError.Value());

		auto bounds = Rect(Point(0, 0), window->Convert(window->GetClientSize()));
		fatalMaskElement->GetRenderer()->Render(bounds);

		auto textBounds = bounds;
		if (textBounds.Width() > 32 && textBounds.Height() > 32)
		{
			textBounds.x1 += 16;
			textBounds.y1 += 16;
			textBounds.x2 -= 16;
			textBounds.y2 -= 16;
		}
		fatalTextElement->GetRenderer()->Render(textBounds);
	}

	void GuiRemoteRendererSingle::RenderDom(Ptr<remoteprotocol::RenderingDom> dom, elements::IGuiGraphicsRenderTarget* rt)
	{
		if (dom->content.element)
		{
			vint index = availableElements.Keys().IndexOf(dom->content.element.Value());
			if (index != -1)
			{
				auto element = availableElements.Values()[index];
				rt->PushClipper(dom->content.validArea, nullptr);
				element->GetRenderer()->Render(dom->content.bounds);
				rt->PopClipper(nullptr);

				if (auto solidLabel = element.Cast<GuiSolidLabelElement>())
				{
					index = solidLabelMeasurings.Keys().IndexOf(dom->content.element.Value());
					if (index != -1)
					{
						auto& measuring = const_cast<SolidLabelMeasuring&>(solidLabelMeasurings.Values()[index]);
						auto minSize = element->GetRenderer()->GetMinSize();

						bool measuringChanged = false;
						if (!measuring.minSize)
						{
							measuringChanged = true;
						}
						else switch (measuring.request)
						{
						case ElementSolidLabelMeasuringRequest::FontHeight:
							if (measuring.minSize.Value().y != minSize.y)
							{
								measuringChanged = true;
							}
							break;
						case ElementSolidLabelMeasuringRequest::TotalSize:
							if (measuring.minSize.Value() != minSize)
							{
								measuringChanged = true;
							}
							break;
						}

						measuring.minSize = minSize;
						if (measuringChanged)
						{
							StoreLabelMeasuring(dom->content.element.Value(), measuring.request, solidLabel, minSize);
						}
					}
				}
			}
		}

		if (dom->children)
		{
			for (auto child : *dom->children.Obj())
			{
				if (child->content.validArea.Width() > 0 && child->content.validArea.Height()> 0)
				{
					RenderDom(child, rt);
				}
			}
		}
	}

	void GuiRemoteRendererSingle::HitTestInternal(Ptr<remoteprotocol::RenderingDom> dom, Point location, Nullable<INativeWindowListener::HitTestResult>& hitTestResult, Nullable<INativeCursor::SystemCursorType>& cursorType)
	{
		if (dom->children)
		{
			for (auto child : *dom->children.Obj())
			{
				if (child->content.validArea.Contains(location))
				{
					HitTestInternal(child, location, hitTestResult, cursorType);

					if (!hitTestResult && child->content.hitTestResult)
					{
						hitTestResult = child->content.hitTestResult;
					}
					if (!cursorType && child->content.cursor)
					{
						cursorType = child->content.cursor;
					}
				}
			}
		}
	}

	void GuiRemoteRendererSingle::HitTest(Ptr<remoteprotocol::RenderingDom> dom, Point location, INativeWindowListener::HitTestResult& hitTestResult, INativeCursor*& cursor)
	{
		Nullable<INativeWindowListener::HitTestResult> hitTestResultNullable;
		Nullable<INativeCursor::SystemCursorType> cursorTypeNullable;
		HitTestInternal(dom, location, hitTestResultNullable, cursorTypeNullable);
		hitTestResult = hitTestResultNullable ? hitTestResultNullable.Value() : INativeWindowListener::NoDecision;
		cursor = cursorTypeNullable ? GetCurrentController()->ResourceService()->GetSystemCursor(cursorTypeNullable.Value()) : GetCurrentController()->ResourceService()->GetDefaultSystemCursor();
	}

	void GuiRemoteRendererSingle::ForceRender()
	{
		supressPaint = true;
		auto rt = GetGuiGraphicsResourceManager()->GetRenderTarget(window);
		rt->StartRendering();
		if (renderingDom)
		{
			RenderDom(renderingDom, rt);
		}
		RenderFatalOverlay(rt);
		auto result = rt->StopRendering();
		window->RedrawContent();
		supressPaint = false;

		switch (result)
		{
		case RenderTargetFailure::ResizeWhileRendering:
			GetGuiGraphicsResourceManager()->ResizeRenderTarget(window);
			needRefresh = true;
			break;
		case RenderTargetFailure::LostDevice:
			UpdateRenderTarget(nullptr);
			GetGuiGraphicsResourceManager()->RecreateRenderTarget(window);
			UpdateRenderTarget(GetGuiGraphicsResourceManager()->GetRenderTarget(window));
			needRefresh = true;
			break;
		default:;
		}
	}

	void GuiRemoteRendererSingle::GlobalTimer()
	{
		if (!disconnectingFromCore)
		{
			DateTime now = DateTime::UtcTime();
			if (now.osMilliseconds - lastCaretTime >= CaretInterval)
			{
				lastCaretTime = now.osMilliseconds;
				OnCaretNotify();
			}
			SendAccumulatedMessages();
		}
		else
		{
			ClearPendingCoreEvents();
		}

		// Between any element destroying, element creating, start rendering
		// and end rendering
		// no refreshing is allowed to avoid flashing issue
		if (supressRefresh) return;
		if (!needRefresh) return;
		needRefresh = false;
		if (!window) return;
		if (!renderingDom && !stoppedByFatalError) return;
		ForceRender();
	}

	void GuiRemoteRendererSingle::Paint()
	{
		if (!supressPaint)
		{
			needRefresh = true;
		}
	}

	INativeWindowListener::HitTestResult GuiRemoteRendererSingle::HitTest(NativePoint location)
	{
		INativeWindowListener::HitTestResult hitTestResult = INativeWindowListener::NoDecision;
		INativeCursor* cursor = nullptr;
		if (renderingDom)
		{
			HitTest(renderingDom, window->Convert(location), hitTestResult, cursor);
		}
		return hitTestResult;
	}
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_RENDERING_DOCUMENT.CPP
***********************************************************************/

namespace vl::presentation::remote_renderer
{
	using namespace collections;
	using namespace elements;
	using namespace remoteprotocol;

/***********************************************************************
* Rendering (Elements -- Document)
***********************************************************************/

	class GuiRemoteDocumentParagraphElement
		: public Object
		, public IGuiGraphicsElement
		, protected IGuiGraphicsRenderer
		, protected IGuiGraphicsRendererFactory
		, protected IGuiGraphicsParagraphCallback
	{
	protected:
		GuiRemoteRendererSingle*											owner = nullptr;
		vint																paragraphId = -1;
		compositions::GuiGraphicsComposition*								ownerComposition = nullptr;
		IGuiGraphicsRenderTarget*											renderTarget = nullptr;

		Ptr<IGuiGraphicsParagraph>											paragraph;
		Nullable<WString>													text;
		bool																wrapLine = false;
		vint																maxWidth = 1;
		remoteprotocol::ElementHorizontalAlignment							alignment = remoteprotocol::ElementHorizontalAlignment::Left;
		Nullable<remoteprotocol::OpenCaretRequest>							caret;

		elements::DocumentTextRunPropertyMap								textRuns;
		elements::DocumentInlineObjectRunPropertyMap						inlineObjectRuns;
		elements::DocumentRunPropertyMap									mergedRuns;

		Dictionary<vint, Rect>												inlineObjectBounds;
		Dictionary<vint, remoteprotocol::DocumentInlineObjectRunProperty>	inlineObjectProps;
		Dictionary<vint, elements::CaretRange>								inlineObjectRanges;

		void SetOwnerComposition(compositions::GuiGraphicsComposition* composition) override
		{
			ownerComposition = composition;
		}

	public:
		GuiRemoteDocumentParagraphElement(GuiRemoteRendererSingle* _owner, vint _paragraphId)
			: owner(_owner)
			, paragraphId(_paragraphId)
		{
		}

		~GuiRemoteDocumentParagraphElement()
		{
		}

		const WString& GetText()
		{
			return text ? text.Value() : WString::Empty;
		}

		IGuiGraphicsParagraph* GetParagraph() const
		{
			return paragraph.Obj();
		}

		// ===== IGuiGraphicsElement =====

		IGuiGraphicsRenderer* GetRenderer() override
		{
			return this;
		}

		compositions::GuiGraphicsComposition* GetOwnerComposition() override
		{
			return ownerComposition;
		}

	protected:

		// ===== IGuiGraphicsRenderer =====

		IGuiGraphicsRendererFactory* GetFactory() override
		{
			return this;
		}

		void Initialize(IGuiGraphicsElement* element) override
		{
		}

		void Finalize() override
		{
		}

		void SetRenderTarget(IGuiGraphicsRenderTarget* _renderTarget) override
		{
			if (renderTarget != _renderTarget)
			{
				renderTarget = _renderTarget;
				paragraph = nullptr;

				if (renderTarget)
				{
					TryRecreateParagraph();
				}
			}
		}

		void Render(Rect bounds) override
		{
			if (paragraph)
			{
				paragraph->Render(bounds);
			}
		}

		void OnElementStateChanged() override
		{
		}

		Size GetMinSize() override
		{
			return {};
		}

		// ===== IGuiGraphicsRendererFactory =====

		IGuiGraphicsRenderer* Create() override
		{
			CHECK_FAIL(L"vl::presentation::remote_renderer::GuiRemoteDocumentParagraphElement::Create()#Not supported.");
		}

		// ===== IGuiGraphicsParagraphCallback =====

		Size OnRenderInlineObject(vint callbackId, Rect location) override
		{
			vint index = inlineObjectBounds.Keys().IndexOf(callbackId);
			if (index == -1 || inlineObjectBounds.Values()[index] != location)
			{
				inlineObjectBounds.Set(callbackId, location);

				remoteprotocol::ElementMeasuring_InlineObjectBounds bounds;
				bounds.elementId = paragraphId;
				bounds.callbackId = callbackId;
				bounds.bounds = location;

				if (!owner->elementMeasurings.inlineObjectBounds)
				{
					owner->elementMeasurings.inlineObjectBounds = Ptr(new List<remoteprotocol::ElementMeasuring_InlineObjectBounds>);
				}
				owner->elementMeasurings.inlineObjectBounds->Add(bounds);
			}
			index = inlineObjectProps.Keys().IndexOf(callbackId);
			if (index == -1) return {};
			return inlineObjectProps.Values()[index].size;
		}

	protected:

		void ApplyProps()
		{
			paragraph->SetWrapLine(wrapLine);
			paragraph->SetMaxWidth(maxWidth);
			paragraph->SetParagraphAlignment(owner->GetAlignment(alignment));
		}

		void ApplyCaret()
		{
			if (caret)
			{
				auto& c = caret.Value();
				paragraph->EnableCaret(c.caret, c.caretColor, c.frontSide);
			}
			else
			{
				paragraph->DisableCaret();
			}
		}

		void ApplyTextRun(elements::CaretRange range, const remoteprotocol::DocumentTextRunProperty& textProp)
		{
			auto start = range.caretBegin;
			auto length = range.caretEnd - range.caretBegin;
			if (length <= 0) return;

			paragraph->SetFont(start, length, textProp.fontProperties.fontFamily);
			paragraph->SetSize(start, length, textProp.fontProperties.size);

			IGuiGraphicsParagraph::TextStyle style = (IGuiGraphicsParagraph::TextStyle)0;
			if (textProp.fontProperties.bold) style = (IGuiGraphicsParagraph::TextStyle)((vint)style | (vint)IGuiGraphicsParagraph::TextStyle::Bold);
			if (textProp.fontProperties.italic) style = (IGuiGraphicsParagraph::TextStyle)((vint)style | (vint)IGuiGraphicsParagraph::TextStyle::Italic);
			if (textProp.fontProperties.underline) style = (IGuiGraphicsParagraph::TextStyle)((vint)style | (vint)IGuiGraphicsParagraph::TextStyle::Underline);
			if (textProp.fontProperties.strikeline) style = (IGuiGraphicsParagraph::TextStyle)((vint)style | (vint)IGuiGraphicsParagraph::TextStyle::Strikeline);
			paragraph->SetStyle(start, length, style);

			paragraph->SetColor(start, length, textProp.textColor);
			paragraph->SetBackgroundColor(start, length, textProp.backgroundColor);
		}

		void ApplyInlineObjectRun(elements::CaretRange range, const remoteprotocol::DocumentInlineObjectRunProperty& inlineProp)
		{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteDocumentParagraphElement::ApplyInlineObjectRun(CaretRange, const DocumentInlineObjectRunProperty&)#"
			auto start = range.caretBegin;
			auto length = range.caretEnd - range.caretBegin;
			if (length <= 0) return;

			Ptr<IGuiGraphicsElement> background;
			if (inlineProp.backgroundElementId != -1)
			{
				vint index = owner->availableElements.Keys().IndexOf(inlineProp.backgroundElementId);
				CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"backgroundElementId not found.");
				background = owner->availableElements.Values()[index];
			}

			IGuiGraphicsParagraph::InlineObjectProperties props;
			props.size = inlineProp.size;
			props.baseline = inlineProp.baseline;
			props.breakCondition = inlineProp.breakCondition;
			props.backgroundColor = inlineProp.backgroundColor;
			props.callbackId = inlineProp.callbackId;
			props.backgroundImage = background;
			CHECK_ERROR(paragraph->SetInlineObject(start, length, props), ERROR_MESSAGE_PREFIX L"SetInlineObject failed.");
#undef ERROR_MESSAGE_PREFIX
		}

		void ApplyRuns()
		{
			auto&& mergedKeys = mergedRuns.Keys();
			for (vint i = 0; i < mergedKeys.Count(); i++)
			{
				auto range = mergedKeys[i];
				auto props = mergedRuns.Values()[i];

				props.Apply(Overloading(
					[&](const remoteprotocol::DocumentTextRunProperty& textProp)
					{
						ApplyTextRun(range, textProp);
					},
					[&](const remoteprotocol::DocumentInlineObjectRunProperty& inlineProp)
					{
						ApplyInlineObjectRun(range, inlineProp);
					}
				));
			}
		}

		void TryRecreateParagraph()
		{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteDocumentParagraphElement::TryRecreateParagraph()#"
			if (!renderTarget) return;
			if (!text) return;

			auto resourceManager = GetGuiGraphicsResourceManager();
			CHECK_ERROR(resourceManager != nullptr, ERROR_MESSAGE_PREFIX L"GetGuiGraphicsResourceManager() returns null.");
			paragraph = resourceManager->GetLayoutProvider()->CreateParagraph(text.Value(), renderTarget, this);
			ApplyProps();
			ApplyRuns();
			ApplyCaret();
#undef ERROR_MESSAGE_PREFIX
		}

	public:

		bool TryGetInlineObjectRunProperty(vint callbackId, remoteprotocol::DocumentInlineObjectRunProperty& outProp) const
		{
			vint index = inlineObjectProps.Keys().IndexOf(callbackId);
			if (index == -1) return false;
			outProp = inlineObjectProps.Values()[index];
			return true;
		}

		void ApplyUpdateAndFillResponse(const remoteprotocol::ElementDesc_DocumentParagraph& arguments, remoteprotocol::UpdateElement_DocumentParagraphResponse& response)
		{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteDocumentParagraphElement::ApplyUpdateAndFillResponse(const remoteprotocol::ElementDesc_DocumentParagraph&, remoteprotocol::UpdateElement_DocumentParagraphResponse&)#"

			wrapLine = arguments.wrapLine;
			maxWidth = arguments.maxWidth;
			alignment = arguments.alignment;

			if (!paragraph)
			{
				CHECK_ERROR(arguments.text, ERROR_MESSAGE_PREFIX L"First update must contain text.");
				text = arguments.text;

				// These should be unnecessary but keep them here so far.
				textRuns.Clear();
				inlineObjectRuns.Clear();
				mergedRuns.Clear();
				inlineObjectBounds.Clear();
				inlineObjectProps.Clear();
				inlineObjectRanges.Clear();

				if (renderTarget)
				{
					TryRecreateParagraph();
				}
			}
			else
			{
				CHECK_ERROR(!arguments.text, ERROR_MESSAGE_PREFIX L"Text is only allowed on first update.");
				ApplyProps();
			}

			if (arguments.removedInlineObjects)
			{
				for (auto callbackId : *arguments.removedInlineObjects.Obj())
				{
					auto&& inlineKeys = inlineObjectRuns.Keys();
					for (vint i = 0; i < inlineKeys.Count(); i++)
					{
						auto range = inlineKeys[i];
						auto prop = inlineObjectRuns.Values()[i];
						if (prop.callbackId == callbackId)
						{
							CHECK_ERROR(elements::ResetInlineObjectRun(inlineObjectRuns, range), ERROR_MESSAGE_PREFIX L"ResetInlineObjectRun failed.");
							break;
						}
					}

					vint index = inlineObjectRanges.Keys().IndexOf(callbackId);
					if (index != -1 && paragraph)
					{
						auto range = inlineObjectRanges.Values()[index];
						paragraph->ResetInlineObject(range.caretBegin, range.caretEnd - range.caretBegin);
					}
					inlineObjectBounds.Remove(callbackId);
					inlineObjectProps.Remove(callbackId);
					inlineObjectRanges.Remove(callbackId);
				}
			}

			if (arguments.runsDiff)
			{
				for (auto run : *arguments.runsDiff.Obj())
				{
					elements::CaretRange range{ run.caretBegin, run.caretEnd };
					run.props.Apply(Overloading(
						[&](const remoteprotocol::DocumentTextRunProperty& textProp)
						{
							elements::DocumentTextRunPropertyOverrides overrides;
							overrides.textColor = textProp.textColor;
							overrides.backgroundColor = textProp.backgroundColor;
							overrides.fontFamily = textProp.fontProperties.fontFamily;
							overrides.size = textProp.fontProperties.size;
							// Convert bool flags back to TextStyle
							elements::IGuiGraphicsParagraph::TextStyle style = (elements::IGuiGraphicsParagraph::TextStyle)0;
							if (textProp.fontProperties.bold) style = (elements::IGuiGraphicsParagraph::TextStyle)((vint)style | (vint)elements::IGuiGraphicsParagraph::TextStyle::Bold);
							if (textProp.fontProperties.italic) style = (elements::IGuiGraphicsParagraph::TextStyle)((vint)style | (vint)elements::IGuiGraphicsParagraph::TextStyle::Italic);
							if (textProp.fontProperties.underline) style = (elements::IGuiGraphicsParagraph::TextStyle)((vint)style | (vint)elements::IGuiGraphicsParagraph::TextStyle::Underline);
							if (textProp.fontProperties.strikeline) style = (elements::IGuiGraphicsParagraph::TextStyle)((vint)style | (vint)elements::IGuiGraphicsParagraph::TextStyle::Strikeline);
							overrides.textStyle = style;
							elements::AddTextRun(textRuns, range, overrides);
						},
						[&](const remoteprotocol::DocumentInlineObjectRunProperty& inlineProp)
						{
							CHECK_ERROR(elements::AddInlineObjectRun(inlineObjectRuns, range, inlineProp), ERROR_MESSAGE_PREFIX L"arguments.runsDiff updated an inline object run incorrectly.");
							inlineObjectProps.Set(inlineProp.callbackId, inlineProp);
							inlineObjectRanges.Set(inlineProp.callbackId, range);
						}
					));
				}
			}

			mergedRuns.Clear();
			elements::MergeRuns(textRuns, inlineObjectRuns, mergedRuns);

			if (arguments.runsDiff && paragraph)
			{
				for (auto run : *arguments.runsDiff.Obj())
				{
					elements::CaretRange range{ run.caretBegin, run.caretEnd };

					run.props.Apply(Overloading(
						[&](const remoteprotocol::DocumentTextRunProperty& textProp)
						{
							ApplyTextRun(range, textProp);
						},
						[&](const remoteprotocol::DocumentInlineObjectRunProperty& inlineProp)
						{
							ApplyInlineObjectRun(range, inlineProp);
						}
					));
				}
			}

			response.documentSize = paragraph->GetSize();
#undef ERROR_MESSAGE_PREFIX
		}

		void OpenCaretAndStore(const remoteprotocol::OpenCaretRequest& arguments)
		{
			caret = arguments;
			ApplyCaret();
		}

		void CloseCaretAndStore()
		{
			caret.Reset();
			ApplyCaret();
		}
	};

	void GuiRemoteRendererSingle::OnCaretNotify()
	{
		for (auto element : From(focusedParagraphElements.Values()).Cast<GuiRemoteDocumentParagraphElement>())
		{
			if (auto paragraph = element->GetParagraph())
			{
				if (paragraph->BlinkCaret())
				{
					needRefresh = true;
				}
			}
		}
	}

	Ptr<IGuiGraphicsElement> GuiRemoteRendererSingle::CreateRemoteDocumentParagraphElement(vint paragraphId)
	{
		return Ptr(new GuiRemoteDocumentParagraphElement(this, paragraphId));
	}

#define PREPARE_DOCUMENT_WRAPPER_RAW(WRAPPER_NAME, ELEMENT_ID)																			\
	vint index = availableElements.Keys().IndexOf(ELEMENT_ID);																			\
	CHECK_ERROR(index != -1, L"GuiRemoteRendererSingle::Request*()#Failed to find IGuiGraphicsParagraph from element id.");				\
	auto WRAPPER_NAME = availableElements.Values()[index].Cast<GuiRemoteDocumentParagraphElement>();									\
	CHECK_ERROR(WRAPPER_NAME, L"GuiRemoteRendererSingle::Request*()#Failed to find IGuiGraphicsParagraph from element id.")				\

#define PREPARE_DOCUMENT_WRAPPER(WRAPPER_NAME, ELEMENT_ID)																				\
	PREPARE_DOCUMENT_WRAPPER_RAW(WRAPPER_NAME, ELEMENT_ID);																				\
	CHECK_ERROR(WRAPPER_NAME->GetParagraph(), L"GuiRemoteRendererSingle::Request*()#The IGuiGraphicsParagraph is not created yet.")		\

	void GuiRemoteRendererSingle::RequestRendererUpdateElement_DocumentParagraph(vint id, const remoteprotocol::ElementDesc_DocumentParagraph& arguments)
	{
		PREPARE_DOCUMENT_WRAPPER_RAW(wrapper, arguments.id);
		UpdateElement_DocumentParagraphResponse response;
		wrapper->ApplyUpdateAndFillResponse(arguments, response);
		events->RespondRendererUpdateElement_DocumentParagraph(id, response);

		if (enabledAutomation)
		{
			vint index = renderingElements.Keys().IndexOf(arguments.id);
			if (index != -1)
			{
				auto& renderingElement = const_cast<RenderingElement&>(renderingElements.Values()[index]);
				remoteprotocol::ElementDesc_DocumentParagraphFull copiedDesc{ arguments };
				if (renderingElement.value)
				{
					if (auto dp = renderingElement.value.Value().TryGet<remoteprotocol::ElementDesc_DocumentParagraphFull>())
					{
						if (!copiedDesc.paragraph.text) copiedDesc.paragraph.text = dp->paragraph.text;
						copiedDesc.caret = dp->caret;
					}
				}
				renderingElement.value = copiedDesc;
			}
		}
	}

	void GuiRemoteRendererSingle::RequestDocumentParagraph_GetCaret(vint id, const remoteprotocol::GetCaretRequest& arguments)
	{
		PREPARE_DOCUMENT_WRAPPER(wrapper, arguments.id);
		GetCaretResponse response;
		response.preferFrontSide = false;
		response.newCaret = wrapper->GetParagraph()->GetCaret(arguments.caret, arguments.relativePosition, response.preferFrontSide);
		events->RespondDocumentParagraph_GetCaret(id, response);
	}

	void GuiRemoteRendererSingle::RequestDocumentParagraph_GetCaretBounds(vint id, const remoteprotocol::GetCaretBoundsRequest& arguments)
	{
		PREPARE_DOCUMENT_WRAPPER(wrapper, arguments.id);
		remoteprotocol::GetCaretBoundsResponse response;
		response.frontSideBounds = Ptr(new List<Rect>);
		response.backSideBounds = Ptr(new List<Rect>);

		vint length = wrapper->GetText().Length();
		auto paragraph = wrapper->GetParagraph();
		for (vint i = 0; i <= length; i++)
		{
			response.frontSideBounds->Add(paragraph->GetCaretBounds(i, true));
			response.backSideBounds->Add(paragraph->GetCaretBounds(i, false));
		}
		events->RespondDocumentParagraph_GetCaretBounds(id, response);
	}

	void GuiRemoteRendererSingle::RequestDocumentParagraph_GetInlineObjectFromPoint(vint id, const remoteprotocol::GetInlineObjectFromPointRequest& arguments)
	{
		PREPARE_DOCUMENT_WRAPPER(wrapper, arguments.id);
		Nullable<remoteprotocol::DocumentRun> result;
		vint start = 0;
		vint length = 0;
		auto props = wrapper->GetParagraph()->GetInlineObjectFromPoint(arguments.point, start, length);
		if (props)
		{
			vint cb = props.Value().callbackId;
			remoteprotocol::DocumentInlineObjectRunProperty inlineProp;
			if (wrapper->TryGetInlineObjectRunProperty(cb, inlineProp))
			{
				remoteprotocol::DocumentRun run;
				run.caretBegin = start;
				run.caretEnd = start + length;
				run.props = inlineProp;
				result = run;
			}
		}
		events->RespondDocumentParagraph_GetInlineObjectFromPoint(id, result);
	}

	void GuiRemoteRendererSingle::RequestDocumentParagraph_GetNearestCaretFromTextPos(vint id, const remoteprotocol::GetNearestCaretFromTextPosRequest& arguments)
	{
		PREPARE_DOCUMENT_WRAPPER(wrapper, arguments.id);
		auto result = wrapper->GetParagraph()->GetNearestCaretFromTextPos(arguments.textPos, arguments.frontSide);
		events->RespondDocumentParagraph_GetNearestCaretFromTextPos(id, result);
	}

	void GuiRemoteRendererSingle::RequestDocumentParagraph_IsValidCaret(vint id, const remoteprotocol::IsValidCaretRequest& arguments)
	{
		PREPARE_DOCUMENT_WRAPPER(wrapper, arguments.id);
		auto result = wrapper->GetParagraph()->IsValidCaret(arguments.caret);
		events->RespondDocumentParagraph_IsValidCaret(id, result);
	}

	void GuiRemoteRendererSingle::RequestDocumentParagraph_OpenCaret(const remoteprotocol::OpenCaretRequest& arguments)
	{
		PREPARE_DOCUMENT_WRAPPER(wrapper, arguments.id);
		wrapper->OpenCaretAndStore(arguments);
		focusedParagraphElements.Set(arguments.id, wrapper);

		if (enabledAutomation)
		{
			vint index = renderingElements.Keys().IndexOf(arguments.id);
			if (index != -1)
			{
				auto& renderingElement = const_cast<RenderingElement&>(renderingElements.Values()[index]);
				if (renderingElement.value)
				{
					renderingElement.value.Value().TryApply(
						[&](remoteprotocol::ElementDesc_DocumentParagraphFull& desc)
						{
							desc.caret = arguments;
						}
					);
				}
			}
		}
	}

	void GuiRemoteRendererSingle::RequestDocumentParagraph_CloseCaret(const vint& arguments)
	{
		PREPARE_DOCUMENT_WRAPPER(wrapper, arguments);
		wrapper->CloseCaretAndStore();
		focusedParagraphElements.Remove(arguments);

		if (enabledAutomation)
		{
			vint index = renderingElements.Keys().IndexOf(arguments);
			if (index != -1)
			{
				auto& renderingElement = const_cast<RenderingElement&>(renderingElements.Values()[index]);
				if (renderingElement.value)
				{
					renderingElement.value.Value().TryApply(
						[](remoteprotocol::ElementDesc_DocumentParagraphFull& desc)
						{
							desc.caret.Reset();
						}
					);
				}
			}
		}
	}

#undef PREPARE_DOCUMENT_WRAPPER
#undef PREPARE_DOCUMENT_WRAPPER_RAW
}


/***********************************************************************
.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_RENDERING_ELEMENTS.CPP
***********************************************************************/

namespace vl::presentation::remote_renderer
{
	using namespace collections;
	using namespace elements;
	using namespace remoteprotocol;

/***********************************************************************
* Rendering (Elemnents)
***********************************************************************/

	void GuiRemoteRendererSingle::RequestRendererUpdateElement_SolidBorder(const remoteprotocol::ElementDesc_SolidBorder& arguments)
	{
		vint index = availableElements.Keys().IndexOf(arguments.id);
		if (index == -1) return;
		auto element = availableElements.Values()[index].Cast<GuiSolidBorderElement>();
		if (!element) return;

		element->SetColor(arguments.borderColor);
		element->SetShape(arguments.shape);
	}

	void GuiRemoteRendererSingle::RequestRendererUpdateElement_SinkBorder(const remoteprotocol::ElementDesc_SinkBorder& arguments)
	{
		vint index = availableElements.Keys().IndexOf(arguments.id);
		if (index == -1) return;
		auto element = availableElements.Values()[index].Cast<Gui3DBorderElement>();
		if (!element) return;

		element->SetColors(arguments.leftTopColor, arguments.rightBottomColor);
	}

	void GuiRemoteRendererSingle::RequestRendererUpdateElement_SinkSplitter(const remoteprotocol::ElementDesc_SinkSplitter& arguments)
	{
		vint index = availableElements.Keys().IndexOf(arguments.id);
		if (index == -1) return;
		auto element = availableElements.Values()[index].Cast<Gui3DSplitterElement>();
		if (!element) return;

		element->SetColors(arguments.leftTopColor, arguments.rightBottomColor);
		element->SetDirection(arguments.direction);
	}

	void GuiRemoteRendererSingle::RequestRendererUpdateElement_SolidBackground(const remoteprotocol::ElementDesc_SolidBackground& arguments)
	{
		vint index = availableElements.Keys().IndexOf(arguments.id);
		if (index == -1) return;
		auto element = availableElements.Values()[index].Cast<GuiSolidBackgroundElement>();
		if (!element) return;

		element->SetColor(arguments.backgroundColor);
		element->SetShape(arguments.shape);
	}

	void GuiRemoteRendererSingle::RequestRendererUpdateElement_GradientBackground(const remoteprotocol::ElementDesc_GradientBackground& arguments)
	{
		vint index = availableElements.Keys().IndexOf(arguments.id);
		if (index == -1) return;
		auto element = availableElements.Values()[index].Cast<GuiGradientBackgroundElement>();
		if (!element) return;

		element->SetColors(arguments.leftTopColor, arguments.rightBottomColor);
		element->SetDirection(arguments.direction);
		element->SetShape(arguments.shape);
	}

	void GuiRemoteRendererSingle::RequestRendererUpdateElement_InnerShadow(const remoteprotocol::ElementDesc_InnerShadow& arguments)
	{
		vint index = availableElements.Keys().IndexOf(arguments.id);
		if (index == -1) return;
		auto element = availableElements.Values()[index].Cast<GuiInnerShadowElement>();
		if (!element) return;

		element->SetColor(arguments.shadowColor);
		element->SetThickness(arguments.thickness);
	}

	void GuiRemoteRendererSingle::RequestRendererUpdateElement_Polygon(const remoteprotocol::ElementDesc_Polygon& arguments)
	{
		vint index = availableElements.Keys().IndexOf(arguments.id);
		if (index == -1) return;
		auto element = availableElements.Values()[index].Cast<GuiPolygonElement>();
		if (!element) return;

		element->SetSize(arguments.size);
		element->SetBorderColor(arguments.borderColor);
		element->SetBackgroundColor(arguments.backgroundColor);

		if (arguments.points && arguments.points->Count() > 0)
		{
			element->SetPoints(&arguments.points->Get(0), arguments.points->Count());
		}
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_RENDERING_IMAGE.CPP
***********************************************************************/

namespace vl::presentation::remote_renderer
{
	using namespace collections;
	using namespace elements;
	using namespace remoteprotocol;

/***********************************************************************
* Rendering (Elements -- Image)
***********************************************************************/

	remoteprotocol::ImageMetadata GuiRemoteRendererSingle::CreateImageMetadata(vint id, INativeImage* image)
	{
		ImageMetadata response;
		response.id = id;
		response.format = image->GetFormat();
		response.frames = Ptr(new List<ImageFrameMetadata>);
		for (vint i = 0; i < image->GetFrameCount(); i++)
		{
			auto frame = image->GetFrame(i);
			response.frames->Add({ frame->GetSize() });
		}

		return response;
	}

	remoteprotocol::ImageMetadata GuiRemoteRendererSingle::CreateImage(const remoteprotocol::ImageCreation& arguments)
	{
		arguments.imageData->SeekFromBegin(0);
		auto image = GetCurrentController()->ImageService()->CreateImageFromStream(*arguments.imageData.Obj());
		if (availableImages.Keys().Contains(arguments.id))
		{
			availableImages.Set(arguments.id, image);
		}
		else
		{
			availableImages.Add(arguments.id, image);
		}
		return CreateImageMetadata(arguments.id, image.Obj());
	}
	
	void GuiRemoteRendererSingle::RequestImageCreated(vint id, const remoteprotocol::ImageCreation& arguments)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestImageCreated(const ImageCreation&)#"
		CHECK_ERROR(!arguments.imageDataOmitted && arguments.imageData, ERROR_MESSAGE_PREFIX L"Binary content of the image is missing.");

		events->RespondImageCreated(id, CreateImage(arguments));
#undef ERROR_MESSAGE_PREFIX
	}

	void GuiRemoteRendererSingle::RequestImageDestroyed(const vint& arguments)
	{
		availableImages.Remove(arguments);
	}

	void GuiRemoteRendererSingle::RequestRendererUpdateElement_ImageFrame(const remoteprotocol::ElementDesc_ImageFrame& arguments)
	{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestRendererUpdateElement_ImageFrame(const arguments&)#"

		vint index = availableElements.Keys().IndexOf(arguments.id);
		if (index == -1) return;
		auto element = availableElements.Values()[index].Cast<GuiImageFrameElement>();
		if (!element) return;

		element->SetAlignments(GetAlignment(arguments.horizontalAlignment), GetAlignment(arguments.verticalAlignment));
		element->SetStretch(arguments.stretch);
		element->SetEnabled(arguments.enabled);

		if (arguments.imageId && arguments.imageCreation)
		{
			CHECK_ERROR(arguments.imageId.Value() == arguments.imageCreation.Value().id, ERROR_MESSAGE_PREFIX L"imageId and imageCreation.id must be identical.");
		}

		if (arguments.imageId)
		{
			if (arguments.imageCreation && !elementMeasurings.createdImages)
			{
				elementMeasurings.createdImages = Ptr(new List<ImageMetadata>);
			}

			vint index = availableImages.Keys().IndexOf(arguments.imageId.Value());
			if (index == -1)
			{
				CHECK_ERROR(arguments.imageCreation && !arguments.imageCreation.Value().imageDataOmitted && arguments.imageCreation.Value().imageData, ERROR_MESSAGE_PREFIX L"Binary content of the image is missing.");

				auto response = CreateImage(arguments.imageCreation.Value());
				element->SetImage(availableImages[response.id], arguments.imageFrame);
				elementMeasurings.createdImages->Add(response);
			}
			else
			{
				auto image = availableImages.Values()[index];
				element->SetImage(image, arguments.imageFrame);
				if (arguments.imageCreation)
				{
					elementMeasurings.createdImages->Add(CreateImageMetadata(arguments.imageId.Value(), image.Obj()));
				}
			}
		}
#undef ERROR_MESSAGE_PREFIX
	}
}

/***********************************************************************
.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_RENDERING_LABEL.CPP
***********************************************************************/

namespace vl::presentation::remote_renderer
{
	using namespace collections;
	using namespace elements;
	using namespace remoteprotocol;

/***********************************************************************
* Rendering (Elemnents -- Label)
***********************************************************************/

	void GuiRemoteRendererSingle::StoreLabelMeasuring(vint id, remoteprotocol::ElementSolidLabelMeasuringRequest request, Ptr<elements::GuiSolidLabelElement> solidLabel, Size minSize)
	{
		switch (request)
		{
		case ElementSolidLabelMeasuringRequest::FontHeight:
			{
				Pair<WString, vint> key = { solidLabel->GetFont().fontFamily,solidLabel->GetFont().size };
				if (fontHeightMeasurings.Contains(key)) return;
				fontHeightMeasurings.Add(key);

				ElementMeasuring_FontHeight response;
				response.fontFamily = key.key;
				response.fontSize = key.value;
				response.height = minSize.y;

				if (!elementMeasurings.fontHeights)
				{
					elementMeasurings.fontHeights = Ptr(new List<ElementMeasuring_FontHeight>);
				}
				elementMeasurings.fontHeights->Add(response);
			}
			break;
		case ElementSolidLabelMeasuringRequest::TotalSize:
			{
				ElementMeasuring_ElementMinSize response;
				response.id = id;
				response.minSize = minSize;

				if (!elementMeasurings.minSizes)
				{
					elementMeasurings.minSizes = Ptr(new List<ElementMeasuring_ElementMinSize>);
				}
				elementMeasurings.minSizes->Add(response);
			}
			break;
		}
	}

	void GuiRemoteRendererSingle::RequestRendererUpdateElement_SolidLabel(const remoteprotocol::ElementDesc_SolidLabel& arguments)
	{
		vint index = availableElements.Keys().IndexOf(arguments.id);
		if (index == -1) return;
		auto element = availableElements.Values()[index].Cast<GuiSolidLabelElement>();
		if (!element) return;

		element->SetColor(arguments.textColor);
		element->SetAlignments(GetAlignment(arguments.horizontalAlignment), GetAlignment(arguments.verticalAlignment));
		element->SetWrapLine(arguments.wrapLine);
		element->SetWrapLineHeightCalculation(arguments.wrapLineHeightCalculation);
		element->SetEllipse(arguments.ellipse);
		element->SetMultiline(arguments.multiline);

		if (arguments.font)
		{
			element->SetFont(arguments.font.Value());
		}
		if (arguments.text)
		{
			element->SetText(arguments.text.Value());
		}

		if (arguments.measuringRequest)
		{
			SolidLabelMeasuring measuring;
			measuring.request = arguments.measuringRequest.Value();
			index = solidLabelMeasurings.Keys().IndexOf(arguments.id);
			if (solidLabelMeasurings.Keys().Contains(arguments.id))
			{
				solidLabelMeasurings.Set(arguments.id, measuring);
			}
			else
			{
				solidLabelMeasurings.Add(arguments.id, measuring);
			}

			StoreLabelMeasuring(arguments.id, measuring.request, element, element->GetRenderer()->GetMinSize());
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENT.CPP
***********************************************************************/

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

/***********************************************************************
DocumentFontSize
***********************************************************************/

		DocumentFontSize DocumentFontSize::Parse(const WString& value)
		{
			if (value.Length() > 0 && value[value.Length() - 1] == L'x')
			{
				return DocumentFontSize(wtof(value.Left(value.Length() - 1)), true);
			}
			else
			{
				return DocumentFontSize(wtof(value), false);
			}
		}

		WString DocumentFontSize::ToString()const
		{
			return ftow(size) + (relative ? L"x" : L"");
		}

/***********************************************************************
DocumentImageRun
***********************************************************************/

		const wchar_t* DocumentImageRun::RepresentationText=L"[Image]";
		const wchar_t* DocumentEmbeddedObjectRun::RepresentationText=L"[EmbeddedObject]";

/***********************************************************************
ExtractTextVisitor
***********************************************************************/

		namespace document_operation_visitors
		{
			class ExtractTextVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				stream::TextWriter&				writer;
				bool							forCaret;

				ExtractTextVisitor(stream::TextWriter& _writer, bool _forCaret)
					:writer(_writer)
					, forCaret(_forCaret)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					for (auto subRun : run->runs)
					{
						subRun->Accept(this);
					}
				}

				void VisitContent(DocumentContentRun* run)
				{
					writer.WriteString(run->GetRepresentationText());
				}

				void Visit(DocumentTextRun* run)override
				{
					VisitContent(run);
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
					if(forCaret)
					{
						VisitContent(run);
					}
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
					if(forCaret)
					{
						VisitContent(run);
					}
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

/***********************************************************************
DocumentParagraphRun
***********************************************************************/

		WString DocumentParagraphRun::GetTextForCaret()
		{
			return ConvertToText(true);
		}

		WString DocumentParagraphRun::GetTextForReading()
		{
			return ConvertToText(false);
		}

		WString DocumentParagraphRun::ConvertToText(bool forCaret)
		{
			return GenerateToStream([&](StreamWriter& writer)
			{
				ConvertToText(writer, forCaret);
			});
		}

		void DocumentParagraphRun::ConvertToText(stream::TextWriter& writer, bool forCaret)
		{
			ExtractTextVisitor visitor(writer, forCaret);
			Accept(&visitor);
		}

/***********************************************************************
DocumentModel

If a style has a parent style, undefined style properties are inherited recursively.
If any style property is still undefined after inheritance, the value of DefaultStyleName will be picked up during rendering.
***********************************************************************/

		const wchar_t* DocumentModel::DefaultStyleName		= L"#Default";
		const wchar_t* DocumentModel::SelectionStyleName	= L"#Selection";
		const wchar_t* DocumentModel::ContextStyleName		= L"#Context";
		const wchar_t* DocumentModel::NormalLinkStyleName	= L"#NormalLink";
		const wchar_t* DocumentModel::ActiveLinkStyleName	= L"#ActiveLink";

		DocumentModel::DocumentModel()
		{
			if (GetCurrentController())
			{
				FontProperties font = GetCurrentController()->ResourceService()->GetDefaultFont();
				auto sp = Ptr(new DocumentStyleProperties);
				sp->face = font.fontFamily;
				sp->size = DocumentFontSize((double)font.size, false);
				sp->color = Color();
				sp->backgroundColor = Color(0, 0, 0, 0);
				sp->bold = font.bold;
				sp->italic = font.italic;
				sp->underline = font.underline;
				sp->strikeline = font.strikeline;
				sp->antialias = font.antialias;
				sp->verticalAntialias = font.verticalAntialias;

				auto style = Ptr(new DocumentStyle);
				style->styles = sp;
				styles.Add(L"#Default", style);
			}
			else
			{
				auto sp = Ptr(new DocumentStyleProperties);
				sp->face = WString::Unmanaged(L"Times New Roman");
				sp->size = DocumentFontSize(8, false);
				sp->color = Color();
				sp->backgroundColor = Color(0, 0, 0, 0);
				sp->bold = false;
				sp->italic = false;
				sp->underline = false;
				sp->strikeline = false;
				sp->antialias = false;
				sp->verticalAntialias = false;

				auto style = Ptr(new DocumentStyle);
				style->styles = sp;
				styles.Add(L"#Default", style);
			}

			{
				auto sp = Ptr(new DocumentStyleProperties);
				sp->color = Color(255, 255, 255);
				sp->backgroundColor = Color(51, 153, 255);

				auto style = Ptr(new DocumentStyle);
				style->styles = sp;
				styles.Add(L"#Selection", style);
			}
			{
				auto sp = Ptr(new DocumentStyleProperties);

				auto style = Ptr(new DocumentStyle);
				style->styles = sp;
				styles.Add(L"#Context", style);
			}
			{
				auto sp = Ptr(new DocumentStyleProperties);
				sp->color = Color(0, 0, 255);
				sp->underline = true;

				auto style = Ptr(new DocumentStyle);
				style->parentStyleName = L"#Context";
				style->styles = sp;
				styles.Add(L"#NormalLink", style);
			}
			{
				auto sp = Ptr(new DocumentStyleProperties);
				sp->color = Color(255, 128, 0);
				sp->underline = true;

				auto style = Ptr(new DocumentStyle);
				style->parentStyleName = L"#Context";
				style->styles = sp;
				styles.Add(L"#ActiveLink", style);
			}
		}

		void DocumentModel::MergeStyle(Ptr<DocumentStyleProperties> style, Ptr<DocumentStyleProperties> parent)
		{
			if(!style->face					&& parent->face)				style->face					=parent->face;
			if(!style->size					&& parent->size)				style->size					=parent->size;
			if(!style->color				&& parent->color)				style->color				=parent->color;
			if(!style->backgroundColor		&& parent->backgroundColor)		style->backgroundColor		=parent->backgroundColor;
			if(!style->bold					&& parent->bold)				style->bold					=parent->bold;
			if(!style->italic				&& parent->italic)				style->italic				=parent->italic;
			if(!style->underline			&& parent->underline)			style->underline			=parent->underline;
			if(!style->strikeline			&& parent->strikeline)			style->strikeline			=parent->strikeline;
			if(!style->antialias			&& parent->antialias)			style->antialias			=parent->antialias;
			if(!style->verticalAntialias	&& parent->verticalAntialias)	style->verticalAntialias	=parent->verticalAntialias;
		}

		void DocumentModel::MergeBaselineStyle(Ptr<DocumentStyleProperties> style, const WString& styleName)
		{
			auto indexDst = styles.Keys().IndexOf(styleName);
			auto sp = Ptr(new DocumentStyleProperties);
			MergeStyle(sp, style);
			if (indexDst != -1)
			{
				MergeStyle(sp, styles.Values()[indexDst]->styles);
			}

			{
				auto ds = Ptr(new DocumentStyle);
				ds->styles = sp;
				if (indexDst != -1)
				{
					ds->parentStyleName = styles.Values()[indexDst]->parentStyleName;
					styles.Set(styleName, ds);
				}
				else
				{
					styles.Add(styleName, ds);
				}
			}

			for (auto style : styles.Values())
			{
				style->resolvedStyles = nullptr;
			}
		}

		void DocumentModel::MergeBaselineStyle(Ptr<DocumentModel> baselineDocument, const WString& styleName)
		{
			auto indexSrc = baselineDocument->styles.Keys().IndexOf(styleName + L"-Override");
			if (indexSrc == -1)
			{
				return;
			}

			auto csp = baselineDocument->styles.Values()[indexSrc]->styles;
			MergeBaselineStyle(csp, styleName);
		}

		void DocumentModel::MergeBaselineStyles(Ptr<DocumentModel> baselineDocument)
		{
			MergeBaselineStyle(baselineDocument, DefaultStyleName);
			MergeBaselineStyle(baselineDocument, SelectionStyleName);
			MergeBaselineStyle(baselineDocument, ContextStyleName);
			MergeBaselineStyle(baselineDocument, NormalLinkStyleName);
			MergeBaselineStyle(baselineDocument, ActiveLinkStyleName);
		}

		void DocumentModel::MergeDefaultFont(const FontProperties& defaultFont)
		{
			auto style = Ptr(new DocumentStyleProperties);

			style->face					=defaultFont.fontFamily;
			style->size					=DocumentFontSize((double)defaultFont.size, false);
			style->bold					=defaultFont.bold;
			style->italic				=defaultFont.italic;
			style->underline			=defaultFont.underline;
			style->strikeline			=defaultFont.strikeline;
			style->antialias			=defaultFont.antialias;
			style->verticalAntialias	=defaultFont.verticalAntialias;

			MergeBaselineStyle(style, DefaultStyleName);
		}

		DocumentModel::ResolvedStyle DocumentModel::GetStyle(Ptr<DocumentStyleProperties> sp, const ResolvedStyle& context)
		{
			FontProperties font;
			font.fontFamily			=sp->face				?sp->face.Value()				:context.style.fontFamily;
			font.bold				=sp->bold				?sp->bold.Value()				:context.style.bold;
			font.italic				=sp->italic				?sp->italic.Value()				:context.style.italic;
			font.underline			=sp->underline			?sp->underline.Value()			:context.style.underline;
			font.strikeline			=sp->strikeline			?sp->strikeline.Value()			:context.style.strikeline;
			font.antialias			=sp->antialias			?sp->antialias.Value()			:context.style.antialias;
			font.verticalAntialias	=sp->verticalAntialias	?sp->verticalAntialias.Value()	:context.style.verticalAntialias;
			Color color				=sp->color				?sp->color.Value()				:context.color;
			Color backgroundColor	=sp->backgroundColor	?sp->backgroundColor.Value()	:context.backgroundColor;

			if (sp->size)
			{
				font.size = (vint)(sp->size.Value().relative ? context.style.size * sp->size.Value().size : sp->size.Value().size);
			}
			else
			{
				font.size = context.style.size;
			}
			return ResolvedStyle(font, color, backgroundColor);
		}

		DocumentModel::ResolvedStyle DocumentModel::GetStyle(const WString& styleName, const ResolvedStyle& context)
		{
			Ptr<DocumentStyle> selectedStyle;
			{
				vint index=styles.Keys().IndexOf(styleName);
				if(index!=-1)
				{
					selectedStyle=styles.Values()[index];
				}
				else
				{
					selectedStyle=styles[L"#Default"];
				}
			}

			if(!selectedStyle->resolvedStyles)
			{
				auto sp = Ptr(new DocumentStyleProperties);
				selectedStyle->resolvedStyles = sp;

				Ptr<DocumentStyle> currentStyle;
				WString currentName = styleName;
				while(true)
				{
					vint index = styles.Keys().IndexOf(currentName);
					if (index == -1) break;
					currentStyle = styles.Values().Get(index);
					currentName = currentStyle->parentStyleName;
					MergeStyle(sp, currentStyle->styles);
				}
			}

			Ptr<DocumentStyleProperties> sp=selectedStyle->resolvedStyles;
			return GetStyle(sp, context);
		}

		WString DocumentModel::GetTextForCaret()
		{
			return ConvertToText(true, WString::Unmanaged(L"\r\n\r\n"));
		}

		WString DocumentModel::GetTextForReading(const WString& paragraphDelimiter)
		{
			return ConvertToText(false, paragraphDelimiter);
		}

		WString DocumentModel::ConvertToText(bool forCaret, const WString& paragraphDelimiter)
		{
			return GenerateToStream([&](StreamWriter& writer)
			{
				ConvertToText(writer, forCaret, paragraphDelimiter);
			});
		}

		void DocumentModel::ConvertToText(stream::TextWriter& writer, bool forCaret, const WString& paragraphDelimiter)
		{
			// TODO: (enumerable) Linq:Aggregate
			for(vint i=0;i<paragraphs.Count();i++)
			{
				Ptr<DocumentParagraphRun> paragraph=paragraphs[i];
				paragraph->ConvertToText(writer, forCaret);
				if(i<paragraphs.Count()-1)
				{
					writer.WriteString(paragraphDelimiter);
				}
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTCLIPBOARD_DOCUMENT.CPP
***********************************************************************/

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

		namespace document_clipboard_visitors
		{
			class TraverseDocumentVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				TraverseDocumentVisitor()
				{
				}

				virtual void VisitContainer(DocumentContainerRun* run)
				{
					for (auto childRun : run->runs)
					{
						childRun->Accept(this);
					}
				}

				void Visit(DocumentTextRun* run)override
				{
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};

			class ModifyDocumentForClipboardVisitor : public TraverseDocumentVisitor
			{
			public:
				ModifyDocumentForClipboardVisitor()
				{
				}

				void VisitContainer(DocumentContainerRun* run)override
				{
					// TODO: (enumerable) foreach:indexed(alterable(reversed))
					for (vint i = run->runs.Count() - 1; i >= 0; i--)
					{
						auto childRun = run->runs[i];
						if (childRun.Cast<DocumentEmbeddedObjectRun>())
						{
							run->runs.RemoveAt(i);
						}
					}
					TraverseDocumentVisitor::VisitContainer(run);
				}
			};

			class CollectImageRunsVisitor : public TraverseDocumentVisitor
			{
			public:
				List<Ptr<DocumentImageRun>> imageRuns;

				CollectImageRunsVisitor()
				{
				}

				void Visit(DocumentImageRun* run)override
				{
					run->source = L"res://Image_" + itow(imageRuns.Count());
					imageRuns.Add(Ptr(run));
				}
			};
		}
		using namespace document_clipboard_visitors;

		void ModifyDocumentForClipboard(Ptr<DocumentModel> model)
		{
			ModifyDocumentForClipboardVisitor visitor;
			for (auto paragraph : model->paragraphs)
			{
				paragraph->Accept(&visitor);
			}
		}

		Ptr<INativeImage> GetImageFromSingleImageDocument(Ptr<DocumentModel> model)
		{
			if (model->paragraphs.Count() != 1) return nullptr;
			Ptr<DocumentContainerRun> container = model->paragraphs[0];
			while (container)
			{
				if (container->runs.Count() != 1) return nullptr;
				if (auto imageRun = container->runs[0].Cast<DocumentImageRun>())
				{
					return imageRun->image;
				}
				else
				{
					container = container->runs[0].Cast<DocumentContainerRun>();
				}
			}
			return nullptr;
		}

		Ptr<DocumentModel> LoadDocumentFromClipboardStream(stream::IStream& clipboardStream)
		{
			auto tempResource = Ptr(new GuiResource);
			auto tempResourceItem = Ptr(new GuiResourceItem);
			tempResource->AddItem(L"Document", tempResourceItem);
			auto tempResolver = Ptr(new GuiResourcePathResolver(tempResource, L""));

			internal::ContextFreeReader reader(clipboardStream);
			{
				WString title;
				vint32_t version = 0;
				reader << title << version;

				if (title != L"WCF_Document" || version < 1)
				{
					return nullptr;
				}
			}

			WString xmlText;
			reader << xmlText;
			List<GuiResourceError> errors;
			auto parser = GetParserManager()->GetParser<XmlDocument>(L"XML");
			auto xml = parser->Parse({}, xmlText, errors);
			if (errors.Count() > 0) return nullptr;

			{
				vint32_t count = 0;
				reader << count;
				for (vint i = 0; i < count; i++)
				{
					MemoryStream memoryStream;
					reader << (IStream&)memoryStream;
					if (auto image = GetCurrentController()->ImageService()->CreateImageFromStream(memoryStream))
					{
						auto imageItem = Ptr(new GuiResourceItem);
						imageItem->SetContent(L"Image", Ptr(new GuiImageData(image, 0)));
						tempResource->AddItem(L"Image_" + itow(i), imageItem);
					}
				}
			}

			auto document = DocumentModel::LoadFromXml(tempResourceItem, xml, tempResolver, errors);
			return document;
		}

		void SaveDocumentToClipboardStream(Ptr<DocumentModel> model, stream::IStream& clipboardStream)
		{
			CollectImageRunsVisitor visitor;
			for (auto paragraph : model->paragraphs)
			{
				paragraph->Accept(&visitor);
			}

			internal::ContextFreeWriter writer(clipboardStream);
			{
				WString title = L"WCF_Document";
				vint32_t version = 1;
				writer << title << version;
			}
			{
				auto xmlText = GenerateToStream([&](StreamWriter& streamWriter)
				{
					auto xml = model->SaveToXml();
					XmlPrint(xml, streamWriter);
				});
				writer << xmlText;
			}
			{
				vint32_t count = (vint32_t)visitor.imageRuns.Count();
				writer << count;

				for (auto imageRun : visitor.imageRuns)
				{
					MemoryStream memoryStream;
					if (imageRun->image)
					{
						auto format = imageRun->image->GetFormat();
						if (format == INativeImage::Gif)
						{
							format = INativeImage::Png;
						}

						imageRun->image->SaveToStream(memoryStream, format);
					}
					
					writer << (stream::IStream&)memoryStream;
				}
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTCLIPBOARD_HTMLFORMAT.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace stream;

		namespace document_clipboard_visitors
		{
			class GenerateHtmlVisitor : public Object, public DocumentRun::IVisitor
			{
				typedef DocumentModel::ResolvedStyle					ResolvedStyle;
			public:
				List<ResolvedStyle>				styles;
				DocumentModel*					model;
				StreamWriter&					writer;

				GenerateHtmlVisitor(DocumentModel* _model, StreamWriter& _writer)
					:model(_model)
					, writer(_writer)
				{
					ResolvedStyle style;
					style.color = Color(0, 0, 0, 0);
					style.backgroundColor = Color(0, 0, 0, 0);
					style = model->GetStyle(DocumentModel::DefaultStyleName, style);
					styles.Add(style);
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					for (auto subRun : run->runs)
					{
						subRun->Accept(this);
					}
				}

				WString ColorToString(Color c)
				{
					auto result = c.ToString();
					if (result.Length() == 9) result = result.Left(7);
					return result;
				}

				void Visit(DocumentTextRun* run)override
				{
					WString text = run->GetRepresentationText();
					if (text.Length() > 0)
					{
						ResolvedStyle style = styles[styles.Count() - 1];

						writer.WriteString(L"<span style=\"");
						if (style.style.bold) writer.WriteString(L"font-weight:bold; ");
						if (style.style.italic) writer.WriteString(L"font-style:italic; ");
						if (style.style.underline && style.style.strikeline) writer.WriteString(L"text-decoration:underline line-through; ");
						else if (style.style.underline) writer.WriteString(L"text-decoration:underline; ");
						else if (style.style.strikeline) writer.WriteString(L"text-decoration:line-through; ");
						if (style.style.fontFamily != L"") writer.WriteString(L"font-family:" + style.style.fontFamily + L"; ");
						if (style.style.size != 0) writer.WriteString(L"font-size:" + itow(style.style.size) + L"px; ");
						if (style.color.a != 0) writer.WriteString(L"color:" + ColorToString(style.color) + L"; ");
						if (style.backgroundColor.a != 0)writer.WriteString(L"background-color:" + ColorToString(style.backgroundColor) + L"; ");
						writer.WriteString(L"\">");

						for (vint i = 0; i < text.Length(); i++)
						{
							switch (wchar_t c = text[i])
							{
							case L'&': writer.WriteString(L"&amp;"); break;
							case L'<': writer.WriteString(L"&lt;"); break;
							case L'>': writer.WriteString(L"&gt;"); break;
							case L'\r': break;
							case L'\n': writer.WriteString(L"<br>"); break;
							case L' ': writer.WriteString(L"&nbsp;"); break;
							case L'\t': writer.WriteString(L"<pre>\t</pre>"); break;
							default: writer.WriteChar(c); break;
							}
						}

						writer.WriteString(L"</span>");
					}
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					ResolvedStyle style = styles[styles.Count() - 1];
					style = model->GetStyle(run->style, style);
					styles.Add(style);
					VisitContainer(run);
					styles.RemoveAt(styles.Count() - 1);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					ResolvedStyle style = styles[styles.Count() - 1];
					style = model->GetStyle(run->styleName, style);
					styles.Add(style);
					VisitContainer(run);
					styles.RemoveAt(styles.Count() - 1);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					writer.WriteString(L"<a href=\"");
					for (vint i = 0; i < run->reference.Length(); i++)
					{
						switch (wchar_t c = run->reference[i])
						{
						case L'&': writer.WriteString(L"&amp;"); break;
						case L'<': writer.WriteString(L"&lt;"); break;
						case L'>': writer.WriteString(L"&gt;"); break;
						case L'"': writer.WriteString(L"&quot;"); break;
						case L'\'': writer.WriteString(L"&#39;"); break;
						default: writer.WriteChar(c); break;
						}
					}
					writer.WriteString(L"\">");

					ResolvedStyle style = styles[styles.Count() - 1];
					style = model->GetStyle((run->normalStyleName == L"" ? DocumentModel::NormalLinkStyleName : run->normalStyleName), style);
					styles.Add(style);
					VisitContainer(run);
					styles.RemoveAt(styles.Count() - 1);

					writer.WriteString(L"</a>");
				}

				void Visit(DocumentImageRun* run)override
				{
					if (run->image)
					{
						auto imageSize = run->GetSize();
						writer.WriteString(L"<img width=\"" + itow(imageSize.x) + L"\" height=\"" + itow(imageSize.y) + L"\" src=\"data:image/");
						auto format = run->image->GetFormat();
						if (format == INativeImage::Gif)
						{
							format = INativeImage::Png;
						}

						switch (format)
						{
						case INativeImage::Bmp: writer.WriteString(L"bmp;base64,"); break;
						case INativeImage::Gif: writer.WriteString(L"gif;base64,"); break;
						case INativeImage::Icon: writer.WriteString(L"icon;base64,"); break;
						case INativeImage::Jpeg: writer.WriteString(L"jpeg;base64,"); break;
						case INativeImage::Png: writer.WriteString(L"png;base64,"); break;
						case INativeImage::Tiff: writer.WriteString(L"tiff;base64,"); break;
						case INativeImage::Wmp: writer.WriteString(L"wmp;base64,"); break;
						default: writer.WriteString(L"unsupported;base64,\"/>"); return;
						}

						MemoryStream memoryStream;
						run->image->SaveToStream(memoryStream, format);
						memoryStream.SeekFromBegin(0);
						while (true)
						{
							vuint8_t bytes[3] = { 0,0,0 };
							vint read = memoryStream.Read(&bytes, sizeof(bytes));
							if (read == 0) break;

							vuint8_t b1 = bytes[0] / (1 << 2);
							vuint8_t b2 = ((bytes[0] % (1 << 2)) << 4) + bytes[1] / (1 << 4);
							vuint8_t b3 = ((bytes[1] % (1 << 4)) << 2) + bytes[2] / (1 << 6);
							vuint8_t b4 = bytes[2] % (1 << 6);

							const wchar_t* BASE64 =
								L"ABCDEFG"
								L"HIJKLMN"
								L"OPQRST"
								L"UVWXYZ"
								L"abcdefg"
								L"hijklmn"
								L"opqrst"
								L"uvwxyz"
								L"0123456789"
								L"+/";
#define BASE64_CHAR(b)		BASE64[b]
							switch (read)
							{
							case 1:
								writer.WriteChar(BASE64_CHAR(b1));
								writer.WriteChar(BASE64_CHAR(b2));
								writer.WriteChar(L'=');
								writer.WriteChar(L'=');
								break;
							case 2:
								writer.WriteChar(BASE64_CHAR(b1));
								writer.WriteChar(BASE64_CHAR(b2));
								writer.WriteChar(BASE64_CHAR(b3));
								writer.WriteChar(L'=');
								break;
							case 3:
								writer.WriteChar(BASE64_CHAR(b1));
								writer.WriteChar(BASE64_CHAR(b2));
								writer.WriteChar(BASE64_CHAR(b3));
								writer.WriteChar(BASE64_CHAR(b4));
								break;
							}
#undef BASE64_CHAR
						}

						writer.WriteString(L"\"/>");
					}
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_clipboard_visitors;

#define HTML_LINE(LINE) LINE "\r\n"

		void SaveDocumentToHtmlUtf8(Ptr<DocumentModel> model, AString& header, AString& content, AString& footer)
		{
			header =
				HTML_LINE("<!DOCTYPE html>")
				HTML_LINE("<html>")
				HTML_LINE("<header>")
				HTML_LINE("<title>GacUI Document 1.0</title>")
				HTML_LINE("<meta charset=\"utf-8\"/>")
				HTML_LINE("</header>")
				HTML_LINE("<body>")
				;

			MemoryStream memoryStream;
			{
				Utf8Encoder encoder;
				EncoderStream encoderStream(memoryStream, encoder);
				StreamWriter writer(encoderStream);
				GenerateHtmlVisitor visitor(model.Obj(), writer);

				// TODO: (enumerable) foreach
				for (auto paragraph : model->paragraphs)
				{
					writer.WriteString(L"<p style=\"text-align:");
					if (paragraph->alignment)
					{
						switch (paragraph->alignment.Value())
						{
						case Alignment::Left: writer.WriteString(L"left;"); break;
						case Alignment::Center: writer.WriteString(L"center;"); break;
						case Alignment::Right: writer.WriteString(L"right;"); break;
						}
					}
					else
					{
						writer.WriteString(L"left;");
					}
					writer.WriteString(L"\">");
					paragraph->Accept(&visitor);
					writer.WriteString(L"</p>\r\n");
				}
			}
			char zero = 0;
			memoryStream.Write(&zero, sizeof(zero));
			content = (const char*)memoryStream.GetInternalBuffer();

			footer =
				HTML_LINE("</body>")
				HTML_LINE("</html>")
				;
		}

		void SaveDocumentToHtmlClipboardStream(Ptr<DocumentModel> model, stream::IStream& clipboardStream)
		{
			AString header, content, footer;
			SaveDocumentToHtmlUtf8(model, header, content, footer);

			char clipboardHeader[] =
				HTML_LINE("StartHTML:-1")
				HTML_LINE("EndHTML:-1")
				HTML_LINE("StartFragment:0000000000")
				HTML_LINE("EndFragment:0000000000")
				;
			char commentStart[] = "<!--StartFragment-->";
			char commentEnd[] = "<!--EndFragment-->";
			vint offsetStart = sizeof(clipboardHeader) - 1 + header.Length() + sizeof(commentStart) - 1;
			vint offsetEnd = offsetStart + content.Length();

			AString offsetStartString = itoa(offsetStart);
			AString offsetEndString = itoa(offsetEnd);
			memcpy(strstr(clipboardHeader, "EndFragment:") - offsetStartString.Length() - 2, offsetStartString.Buffer(), offsetStartString.Length());
			memcpy(clipboardHeader + sizeof(clipboardHeader) - 1 - offsetEndString.Length() - 2, offsetEndString.Buffer(), offsetEndString.Length());

			clipboardStream.Write(clipboardHeader, sizeof(clipboardHeader) - 1);
			if (header.Length() > 0) clipboardStream.Write((void*)header.Buffer(), header.Length());
			clipboardStream.Write(commentStart, sizeof(commentStart) - 1);
			if (content.Length() > 0) clipboardStream.Write((void*)content.Buffer(), content.Length());
			clipboardStream.Write(commentEnd, sizeof(commentEnd) - 1);
			if (footer.Length() > 0) clipboardStream.Write((void*)footer.Buffer(), footer.Length());
		}

#undef HTML_LINE
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTCLIPBOARD_RICHTEXTFORMAT.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace stream;

		namespace document_clipboard_visitors
		{
			class GenerateRtfVisitor : public Object, public DocumentRun::IVisitor
			{
				typedef DocumentModel::ResolvedStyle					ResolvedStyle;
			public:
				List<ResolvedStyle>				styles;
				DocumentModel*					model;
				StreamWriter&					writer;

				List<WString>&					fontTable;
				List<Color>&					colorTable;
				Dictionary<WString, vint>		fontIndex;
				Dictionary<Color, vint>			colorIndex;

				vint GetFont(const WString& fontName)
				{
					vint index = fontIndex.Keys().IndexOf(fontName);
					if (index == -1)
					{
						index = fontTable.Add(fontName);
						fontIndex.Add(fontName, index);
						return index;
					}
					return fontIndex.Values()[index];
				}

				vint GetColor(Color color)
				{
					if (color.a == 0) return 0;
					vint index = colorIndex.Keys().IndexOf(color);
					if (index == -1)
					{
						index = colorTable.Add(color) + 1;
						colorIndex.Add(color, index);
						return index;
					}
					return colorIndex.Values()[index];
				}

				GenerateRtfVisitor(DocumentModel* _model, List<WString>& _fontTable, List<Color>& _colorTable, StreamWriter& _writer)
					:model(_model)
					, writer(_writer)
					, fontTable(_fontTable)
					, colorTable(_colorTable)
				{
					ResolvedStyle style;
					style.color = Color(0, 0, 0, 0);
					style.backgroundColor = Color(0, 0, 0, 0);
					style = model->GetStyle(DocumentModel::DefaultStyleName, style);
					styles.Add(style);
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					for (auto subRun : run->runs)
					{
						subRun->Accept(this);
					}
				}

				void Visit(DocumentTextRun* run)override
				{
					WString text = run->GetRepresentationText();
					if (text.Length() > 0)
					{
						ResolvedStyle style = styles[styles.Count() - 1];

						writer.WriteString(L"{\\f" + itow(GetFont(style.style.fontFamily)));
						writer.WriteString(L"\\fs" + itow((vint)(style.style.size * 1.5)));
						writer.WriteString(L"\\cf" + itow(GetColor(style.color)));
						writer.WriteString(L"\\cb" + itow(GetColor(style.backgroundColor)));
						writer.WriteString(L"\\chshdng" + itow(GetColor(style.backgroundColor)));
						writer.WriteString(L"\\chcbpat" + itow(GetColor(style.backgroundColor)));

						if (style.style.bold) writer.WriteString(L"\\b");
						if (style.style.italic) writer.WriteString(L"\\i");
						if (style.style.underline) writer.WriteString(L"\\ul");
						if (style.style.strikeline) writer.WriteString(L"\\strike");

						for (vint i = 0; i < text.Length(); i++)
						{
							writer.WriteString(L"\\u" + itow(text[i]));
						}

						writer.WriteString(L"}");
					}
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					ResolvedStyle style = styles[styles.Count() - 1];
					style = model->GetStyle(run->style, style);
					styles.Add(style);
					VisitContainer(run);
					styles.RemoveAt(styles.Count() - 1);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					ResolvedStyle style = styles[styles.Count() - 1];
					style = model->GetStyle(run->styleName, style);
					styles.Add(style);
					VisitContainer(run);
					styles.RemoveAt(styles.Count() - 1);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					ResolvedStyle style = styles[styles.Count() - 1];
					style = model->GetStyle((run->normalStyleName == L"" ? DocumentModel::NormalLinkStyleName : run->normalStyleName), style);
					styles.Add(style);
					VisitContainer(run);
					styles.RemoveAt(styles.Count() - 1);
				}

				void Visit(DocumentImageRun* run)override
				{
					if (run->image)
					{
						writer.WriteString(L"{\\pict\\pngblip");
						auto imageSize = run->GetSize();
						writer.WriteString(L"\\picw" + itow(imageSize.x) + L"\\pich" + itow(imageSize.y));
						writer.WriteString(L"\\picwgoal" + itow(imageSize.x * 15) + L"\\pichgoal" + itow(imageSize.y * 15) + L" ");

						MemoryStream memoryStream;
						run->image->SaveToStream(memoryStream, INativeImage::Png);
						vint count = (vint)memoryStream.Size();
						vuint8_t* buffer = (vuint8_t*)memoryStream.GetInternalBuffer();
						for (vint i = 0; i < count; i++)
						{
							writer.WriteChar(L"0123456789abcdef"[buffer[i] / 16]);
							writer.WriteChar(L"0123456789abcdef"[buffer[i] % 16]);
						}

						writer.WriteString(L"}");
					}
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_clipboard_visitors;

		void SaveDocumentToRtf(Ptr<DocumentModel> model, AString& rtf)
		{
			List<WString> fontTable;
			List<Color> colorTable;
			MemoryStream bodyStream;
			{
				StreamWriter writer(bodyStream);
				GenerateRtfVisitor visitor(model.Obj(), fontTable, colorTable, writer);

				for (auto paragraph : model->paragraphs)
				{
					if (paragraph->alignment)
					{
						switch (paragraph->alignment.Value())
						{
						case Alignment::Left: writer.WriteString(L"\\ql{"); break;
						case Alignment::Center: writer.WriteString(L"\\qc{"); break;
						case Alignment::Right: writer.WriteString(L"\\qr{"); break;
						}
					}
					else
					{
						writer.WriteString(L"\\ql{");
					}
					paragraph->Accept(&visitor);
					writer.WriteString(L"}\\par");
				}
			}

			MemoryStream rtfStream;
			{
				Utf8Encoder encoder;
				EncoderStream encoderStream(rtfStream, encoder);
				StreamWriter writer(encoderStream);

				writer.WriteString(L"{\\rtf1\\ansi\\deff0{\\fonttbl");
				for (auto [fontName, index] : indexed(fontTable))
				{
					writer.WriteString(L"{\\f");
					writer.WriteString(itow(index));
					writer.WriteString(L" ");
					writer.WriteString(fontName);
					writer.WriteString(L";}");
				}

				writer.WriteString(L"}{\\colortbl");
				for (auto [color, index] : indexed(colorTable))
				{
					writer.WriteString(L";\\red");
					writer.WriteString(itow(color.r));
					writer.WriteString(L"\\green");
					writer.WriteString(itow(color.g));
					writer.WriteString(L"\\blue");
					writer.WriteString(itow(color.b));
				}

				writer.WriteString(L";}{\\*\\generator GacUI Document 1.0}\\uc0");
				{
					bodyStream.SeekFromBegin(0);
					StreamReader reader(bodyStream);
					writer.WriteString(reader.ReadToEnd());
				}
				writer.WriteString(L"}");
			}
			char zero = 0;
			rtfStream.Write(&zero, sizeof(zero));
			rtf = (const char*)rtfStream.GetInternalBuffer();
		}

		void SaveDocumentToRtfStream(Ptr<DocumentModel> model, stream::IStream& rtfStream)
		{
			AString rtf;
			SaveDocumentToRtf(model, rtf);
			rtfStream.Write((void*)rtf.Buffer(), rtf.Length());
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_ADDCONTAINER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace document_editor;

/***********************************************************************
Insert container runs on top of all text ranges that intersect with the specified range
AddStyleVisitor		: Apply a style on the specified range
AddHyperlinkVisitor	: Apply a hyperlink on the specified range
AddStyleNameVisitor	: Apply a style name on the specified range
***********************************************************************/

		namespace document_operation_visitors
		{
			class AddContainerVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				RunRangeMap&							runRanges;
				vint									start;
				vint									end;
				bool									insertStyle;

				virtual Ptr<DocumentContainerRun>		CreateContainer() = 0;

				AddContainerVisitor(RunRangeMap& _runRanges, vint _start, vint _end)
					:runRanges(_runRanges)
					, start(_start)
					, end(_end)
					, insertStyle(false)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					// TODO: (enumerable) foreach:indexed(alterable(reversed))
					for (vint i = run->runs.Count() - 1; i >= 0; i--)
					{
						Ptr<DocumentRun> subRun = run->runs[i];
						RunRange range = runRanges[subRun.Obj()];
						if (range.start<end && start<range.end)
						{
							insertStyle = false;
							subRun->Accept(this);
							if (insertStyle)
							{
								Ptr<DocumentContainerRun> containerRun = CreateContainer();
								run->runs.RemoveAt(i);
								containerRun->runs.Add(subRun);
								run->runs.Insert(i, containerRun);
							}
						}
					}
					insertStyle = false;
				}

				void Visit(DocumentTextRun* run)override
				{
					insertStyle = true;
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
					insertStyle = false;
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
					insertStyle = false;
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};

			class AddStyleVisitor : public AddContainerVisitor
			{
			public:
				Ptr<DocumentStyleProperties>	style;

				Ptr<DocumentContainerRun> CreateContainer()override
				{
					auto containerRun = Ptr(new DocumentStylePropertiesRun);
					containerRun->style = CopyStyle(style);
					return containerRun;
				}

				AddStyleVisitor(RunRangeMap& _runRanges, vint _start, vint _end, Ptr<DocumentStyleProperties> _style)
					:AddContainerVisitor(_runRanges, _start, _end)
					, style(_style)
				{
				}
			};

			class AddHyperlinkVisitor : public AddContainerVisitor
			{
			public:
				WString							reference;
				WString							normalStyleName;
				WString							activeStyleName;

				Ptr<DocumentContainerRun> CreateContainer()override
				{
					auto containerRun = Ptr(new DocumentHyperlinkRun);
					containerRun->reference = reference;
					containerRun->normalStyleName = normalStyleName;
					containerRun->activeStyleName = activeStyleName;
					containerRun->styleName = normalStyleName;
					return containerRun;
				}

				AddHyperlinkVisitor(RunRangeMap& _runRanges, vint _start, vint _end, const WString& _reference, const WString& _normalStyleName, const WString& _activeStyleName)
					:AddContainerVisitor(_runRanges, _start, _end)
					, reference(_reference)
					, normalStyleName(_normalStyleName)
					, activeStyleName(_activeStyleName)
				{
				}
			};

			class AddStyleNameVisitor : public AddContainerVisitor
			{
			public:
				WString							styleName;

				Ptr<DocumentContainerRun> CreateContainer()override
				{
					auto containerRun = Ptr(new DocumentStyleApplicationRun);
					containerRun->styleName = styleName;
					return containerRun;
				}

				AddStyleNameVisitor(RunRangeMap& _runRanges, vint _start, vint _end, const WString& _styleName)
					:AddContainerVisitor(_runRanges, _start, _end)
					, styleName(_styleName)
				{
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			void AddStyle(DocumentParagraphRun* run, RunRangeMap& runRanges, vint start, vint end, Ptr<DocumentStyleProperties> style)
			{
				AddStyleVisitor visitor(runRanges, start, end, style);
				run->Accept(&visitor);
			}

			void AddHyperlink(DocumentParagraphRun* run, RunRangeMap& runRanges, vint start, vint end, const WString& reference, const WString& normalStyleName, const WString& activeStyleName)
			{
				AddHyperlinkVisitor visitor(runRanges, start, end, reference, normalStyleName, activeStyleName);
				run->Accept(&visitor);
			}

			void AddStyleName(DocumentParagraphRun* run, RunRangeMap& runRanges, vint start, vint end, const WString& styleName)
			{
				AddStyleNameVisitor visitor(runRanges, start, end, styleName);
				run->Accept(&visitor);
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_CLEARUNNECESSARYRUN.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace document_editor;

/***********************************************************************
Clear all runs that have an empty length
***********************************************************************/

		namespace document_operation_visitors
		{
			class ClearRunVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				vint							start;

				ClearRunVisitor()
					:start(0)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					// TODO: (enumerable) foreach:indexed(alterable(reversed))
					for (vint i = run->runs.Count() - 1; i >= 0; i--)
					{
						vint oldStart = start;
						run->runs[i]->Accept(this);
						if (oldStart == start)
						{
							run->runs.RemoveAt(i);
						}
					}
				}

				void VisitContent(DocumentContentRun* run)
				{
					start += run->GetRepresentationText().Length();
				}

				void Visit(DocumentTextRun* run)override
				{
					VisitContent(run);
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
					VisitContent(run);
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
					VisitContent(run);
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

/***********************************************************************
Ensure DocumentStylePropertiesRun doesn't have a child which is another DocumentStylePropertiesRun
Remove DocumentStylePropertiesRun's property if it set a value but doesn't change the output
Remove DocumentStylePropertiesRun if it is empty or contains no text run
***********************************************************************/

		namespace document_operation_visitors
		{
			class CompressStyleRunVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				DocumentModel*							model;
				List<DocumentModel::ResolvedStyle>		resolvedStyles;
				List<Ptr<DocumentRun>>					replacedRuns;

				CompressStyleRunVisitor(DocumentModel* _model)
					:model(_model)
				{
					DocumentModel::ResolvedStyle resolvedStyle;
					resolvedStyle = model->GetStyle(DocumentModel::DefaultStyleName, resolvedStyle);
					resolvedStyles.Add(resolvedStyle);
				}

				const DocumentModel::ResolvedStyle& GetCurrentResolvedStyle()
				{
					return resolvedStyles[resolvedStyles.Count() - 1];
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					// TODO: (enumerable) foreach:indexed(alterable)
					for (vint i = 0; i < run->runs.Count(); i++)
					{
						Ptr<DocumentRun> subRun = run->runs[i];
						replacedRuns.Clear();
						subRun->Accept(this);
						if (replacedRuns.Count() > 0)
						{
							run->runs.RemoveAt(i);
							// TODO: (enumerable) foreach
							for (vint j = 0; j < replacedRuns.Count(); j++)
							{
								run->runs.Insert(i + j, replacedRuns[j]);
							}
							i--;
						}
					}
				}

				void Visit(DocumentTextRun* run)override
				{
				}

				bool OnlyImageOrObject(DocumentContainerRun* run)
				{
					bool onlyImageOrObject = true;
					for (auto subRun : run->runs)
					{
						if (!subRun.Cast<DocumentImageRun>() && !subRun.Cast<DocumentEmbeddedObjectRun>())
						{
							onlyImageOrObject = false;
							break;
						}
					}
					return onlyImageOrObject;
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					if (OnlyImageOrObject(run))
					{
						CopyFrom(replacedRuns, run->runs);
						return;
					}

					const DocumentModel::ResolvedStyle& currentResolvedStyle = GetCurrentResolvedStyle();
					DocumentModel::ResolvedStyle resolvedStyle = model->GetStyle(run->style, currentResolvedStyle);

					if (currentResolvedStyle.style.fontFamily			== resolvedStyle.style.fontFamily)			run->style->face =				Nullable<WString>();
					if (currentResolvedStyle.style.size					== resolvedStyle.style.size)				run->style->size =				Nullable<DocumentFontSize>();
					if (currentResolvedStyle.color						== resolvedStyle.color)						run->style->color =				Nullable<Color>();
					if (currentResolvedStyle.backgroundColor			== resolvedStyle.backgroundColor)			run->style->backgroundColor =	Nullable<Color>();
					if (currentResolvedStyle.style.bold					== resolvedStyle.style.bold)				run->style->bold =				Nullable<bool>();
					if (currentResolvedStyle.style.italic				== resolvedStyle.style.italic)				run->style->italic =			Nullable<bool>();
					if (currentResolvedStyle.style.underline			== resolvedStyle.style.underline)			run->style->underline =			Nullable<bool>();
					if (currentResolvedStyle.style.strikeline			== resolvedStyle.style.strikeline)			run->style->strikeline =		Nullable<bool>();
					if (currentResolvedStyle.style.antialias			== resolvedStyle.style.antialias)			run->style->antialias =			Nullable<bool>();
					if (currentResolvedStyle.style.verticalAntialias	== resolvedStyle.style.verticalAntialias)	run->style->verticalAntialias =	Nullable<bool>();

					if (run->style->face)				goto CONTINUE_PROCESSING;
					if (run->style->size)				goto CONTINUE_PROCESSING;
					if (run->style->color)				goto CONTINUE_PROCESSING;
					if (run->style->backgroundColor)	goto CONTINUE_PROCESSING;
					if (run->style->bold)				goto CONTINUE_PROCESSING;
					if (run->style->italic)				goto CONTINUE_PROCESSING;
					if (run->style->underline)			goto CONTINUE_PROCESSING;
					if (run->style->strikeline)			goto CONTINUE_PROCESSING;
					if (run->style->antialias)			goto CONTINUE_PROCESSING;
					if (run->style->verticalAntialias)	goto CONTINUE_PROCESSING;
					CopyFrom(replacedRuns, run->runs);
					return;

				CONTINUE_PROCESSING:
					if (From(run->runs).Cast<DocumentStylePropertiesRun>().First(nullptr) != nullptr)
					{
						for (auto subRun : run->runs)
						{
							if (auto styleRun = subRun.Cast<DocumentStylePropertiesRun>())
							{
								DocumentModel::MergeStyle(styleRun->style, run->style);
								replacedRuns.Add(styleRun);
							}
							else
							{
								auto parentRun = CopyRun(run).Cast<DocumentStylePropertiesRun>();
								parentRun->runs.Add(subRun);
								replacedRuns.Add(parentRun);
							}
						}
						return;
					}

					resolvedStyles.Add(resolvedStyle);
					VisitContainer(run);
					resolvedStyles.RemoveAt(resolvedStyles.Count() - 1);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					if (OnlyImageOrObject(run))
					{
						CopyFrom(replacedRuns, run->runs);
						return;
					}

					const DocumentModel::ResolvedStyle& currentResolvedStyle = GetCurrentResolvedStyle();
					DocumentModel::ResolvedStyle resolvedStyle = model->GetStyle(run->styleName, currentResolvedStyle);
					resolvedStyles.Add(resolvedStyle);
					VisitContainer(run);
					resolvedStyles.RemoveAt(resolvedStyles.Count() - 1);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					const DocumentModel::ResolvedStyle& currentResolvedStyle = GetCurrentResolvedStyle();
					DocumentModel::ResolvedStyle resolvedStyle = model->GetStyle(run->styleName, currentResolvedStyle);
					resolvedStyles.Add(resolvedStyle);
					VisitContainer(run);
					resolvedStyles.RemoveAt(resolvedStyles.Count() - 1);
				}

				void Visit(DocumentImageRun* run)override
				{
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

/***********************************************************************
Merge sibling runs if they are exactly the same
***********************************************************************/

		namespace document_operation_visitors
		{
			class MergeSiblingRunVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				Ptr<DocumentRun>						nextRun;
				Ptr<DocumentRun>						replacedRun;

				void Visit(DocumentTextRun* run)override
				{
					if (auto sibilingRun = nextRun.Cast<DocumentTextRun>())
					{
						run->text += sibilingRun->text;
						replacedRun = Ptr(run);
					}
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					if (auto sibilingRun = nextRun.Cast<DocumentStylePropertiesRun>())
					{
						if (run->style->face !=					sibilingRun->style->face)				return;
						if (run->style->size !=					sibilingRun->style->size)				return;
						if (run->style->color !=				sibilingRun->style->color)				return;
						if (run->style->backgroundColor !=		sibilingRun->style->backgroundColor)	return;
						if (run->style->bold !=					sibilingRun->style->bold)				return;
						if (run->style->italic !=				sibilingRun->style->italic)				return;
						if (run->style->underline !=			sibilingRun->style->underline)			return;
						if (run->style->strikeline !=			sibilingRun->style->strikeline)			return;
						if (run->style->antialias !=			sibilingRun->style->antialias)			return;
						if (run->style->verticalAntialias !=	sibilingRun->style->verticalAntialias)	return;

						CopyFrom(run->runs, sibilingRun->runs, true);
						replacedRun = Ptr(run);
					}
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					if (auto sibilingRun = nextRun.Cast<DocumentStyleApplicationRun>())
					{
						if (run->styleName == sibilingRun->styleName)
						{
							CopyFrom(run->runs, sibilingRun->runs, true);
							replacedRun = Ptr(run);
						}
					}
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					if (auto sibilingRun = nextRun.Cast<DocumentHyperlinkRun>())
					{
						if (run->styleName == sibilingRun->styleName &&
							run->normalStyleName == sibilingRun->normalStyleName &&
							run->activeStyleName == sibilingRun->activeStyleName &&
							run->reference == sibilingRun->reference)
						{
							CopyFrom(run->runs, sibilingRun->runs, true);
							replacedRun = Ptr(run);
						}
					}
				}

				void Visit(DocumentImageRun* run)override
				{
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}

				void Visit(DocumentParagraphRun* run)override
				{
				}
			};

			class MergeSiblingRunRecursivelyVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				Ptr<DocumentRun>						replacedRun;
				Ptr<DocumentRun>						nextRun;

				void VisitContainer(DocumentContainerRun* run)
				{
					// TODO: (enumerable) foreach:indexed(alterable(reversed))
					for (vint i = 0; i < run->runs.Count() - 1; i++)
					{
						auto currentRun = run->runs[i];
						auto nextRun = run->runs[i + 1];

						MergeSiblingRunVisitor visitor;
						visitor.nextRun = nextRun;
						currentRun->Accept(&visitor);

						if (visitor.replacedRun)
						{
							run->runs.RemoveAt(i + 1);
							run->runs[i] = visitor.replacedRun;
							i--;
						}
					}

					// TODO: (enumerable) foreach
					for (vint i = 0; i < run->runs.Count() - 1; i++)
					{
						run->runs[i]->Accept(this);
					}
				}

				void Visit(DocumentTextRun* run)override
				{
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			void ClearUnnecessaryRun(DocumentParagraphRun* run, DocumentModel* model)
			{
				{
					ClearRunVisitor visitor;
					run->Accept(&visitor);
				}
				{
					CompressStyleRunVisitor visitor(model);
					run->Accept(&visitor);
				}
				{
					MergeSiblingRunRecursivelyVisitor visitor;
					run->Accept(&visitor);
				}
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_CLONERUN.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace document_editor;

/***********************************************************************
Clone the current run without its children
If clonedRun field is assigned then it will be added to the cloned container run
***********************************************************************/

		namespace document_operation_visitors
		{
			class CloneRunVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				Ptr<DocumentRun>				clonedRun;

				CloneRunVisitor(Ptr<DocumentRun> subRun)
					:clonedRun(subRun)
				{
				}

				void VisitContainer(Ptr<DocumentContainerRun> cloned)
				{
					if (clonedRun)
					{
						cloned->runs.Add(clonedRun);
					}
					clonedRun = cloned;
				}

				void Visit(DocumentTextRun* run)override
				{
					auto cloned = Ptr(new DocumentTextRun);
					cloned->text = run->text;
					clonedRun = cloned;
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					auto cloned = Ptr(new DocumentStylePropertiesRun);
					cloned->style = CopyStyle(run->style);
					VisitContainer(cloned);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					auto cloned = Ptr(new DocumentStyleApplicationRun);
					cloned->styleName = run->styleName;

					VisitContainer(cloned);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					auto cloned = Ptr(new DocumentHyperlinkRun);
					cloned->styleName = run->styleName;
					cloned->normalStyleName = run->normalStyleName;
					cloned->activeStyleName = run->activeStyleName;
					cloned->reference = run->reference;

					VisitContainer(cloned);
				}

				void Visit(DocumentImageRun* run)override
				{
					auto cloned = Ptr(new DocumentImageRun);
					cloned->sizeOverride = run->sizeOverride;
					cloned->baseline = run->baseline;
					cloned->image = run->image;
					cloned->frameIndex = run->frameIndex;
					cloned->source = run->source;
					clonedRun = cloned;
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
					auto cloned = Ptr(new DocumentEmbeddedObjectRun);
					cloned->name = run->name;
					clonedRun = cloned;
				}

				void Visit(DocumentParagraphRun* run)override
				{
					auto cloned = Ptr(new DocumentParagraphRun);
					cloned->alignment = run->alignment;

					VisitContainer(cloned);
				}
			};
		}
		using namespace document_operation_visitors;

/***********************************************************************
Clone the current run with its children
***********************************************************************/

		namespace document_operation_visitors
		{
			class CloneRunRecursivelyVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				Ptr<DocumentRun>				clonedRun;
				RunRangeMap&					runRanges;
				vint							start;
				vint							end;
				bool							deepCopy;

				CloneRunRecursivelyVisitor(RunRangeMap& _runRanges, vint _start, vint _end, bool _deepCopy)
					:runRanges(_runRanges)
					, start(_start)
					, end(_end)
					, deepCopy(_deepCopy)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					clonedRun = 0;
					RunRange range = runRanges[run];
					if (range.start <= end && start <= range.end)
					{
						if (start <= range.start && range.end <= end && !deepCopy)
						{
							clonedRun = Ptr(run);
						}
						else
						{
							Ptr<DocumentContainerRun> containerRun = CopyRun(run).Cast<DocumentContainerRun>();
							for (auto subRun : run->runs)
							{
								subRun->Accept(this);
								if (clonedRun)
								{
									containerRun->runs.Add(clonedRun);
								}
							}
							clonedRun = containerRun;
						}
					}
				}

				void Visit(DocumentTextRun* run)override
				{
					clonedRun = 0;
					RunRange range = runRanges[run];
					if (range.start<end && start<range.end)
					{
						if (start <= range.start && range.end <= end)
						{
							if (deepCopy)
							{
								clonedRun = CopyRun(run);
							}
							else
							{
								clonedRun = Ptr(run);
							}
						}
						else
						{
							auto textRun = Ptr(new DocumentTextRun);
							vint copyStart = start>range.start ? start : range.start;
							vint copyEnd = end<range.end ? end : range.end;
							if (copyStart<copyEnd)
							{
								textRun->text = run->text.Sub(copyStart - range.start, copyEnd - copyStart);
							}
							clonedRun = textRun;
						}
					}
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
					clonedRun = 0;
					RunRange range = runRanges[run];
					if (range.start<end && start<range.end)
					{
						if (deepCopy)
						{
							clonedRun = CopyRun(run);
						}
						else
						{
							clonedRun = Ptr(run);
						}
					}
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
					clonedRun = 0;
					RunRange range = runRanges[run];
					if (range.start<end && start<range.end)
					{
						if (deepCopy)
						{
							clonedRun = CopyRun(run);
						}
						else
						{
							clonedRun = Ptr(run);
						}
					}
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			bool CompareStyleProperties(Ptr<DocumentStyleProperties> a, Ptr<DocumentStyleProperties> b)
			{
				if (!a && !b) return true;
				if (!a || !b) return false;
				return a->face == b->face
					&& a->size == b->size
					&& a->color == b->color
					&& a->backgroundColor == b->backgroundColor
					&& a->bold == b->bold
					&& a->italic == b->italic
					&& a->underline == b->underline
					&& a->strikeline == b->strikeline
					&& a->antialias == b->antialias
					&& a->verticalAntialias == b->verticalAntialias;
			}

			Ptr<DocumentStyleProperties> CopyStyle(Ptr<DocumentStyleProperties> style)
			{
				if (!style) return nullptr;
				auto newStyle = Ptr(new DocumentStyleProperties);

				newStyle->face = style->face;
				newStyle->size = style->size;
				newStyle->color = style->color;
				newStyle->backgroundColor = style->backgroundColor;
				newStyle->bold = style->bold;
				newStyle->italic = style->italic;
				newStyle->underline = style->underline;
				newStyle->strikeline = style->strikeline;
				newStyle->antialias = style->antialias;
				newStyle->verticalAntialias = style->verticalAntialias;

				return newStyle;
			}

			Ptr<DocumentRun> CopyRun(DocumentRun* run)
			{
				CloneRunVisitor visitor(0);
				run->Accept(&visitor);
				return visitor.clonedRun;
			}

			Ptr<DocumentRun> CopyStyledText(List<DocumentContainerRun*>& styleRuns, const WString& text)
			{
				auto textRun = Ptr(new DocumentTextRun);
				textRun->text = text;

				CloneRunVisitor visitor(textRun);
				// TODO: (enumerable) foreach:reversed
				for (vint i = styleRuns.Count() - 1; i >= 0; i--)
				{
					styleRuns[i]->Accept(&visitor);
				}

				return visitor.clonedRun;
			}

			Ptr<DocumentRun> CopyRunRecursively(DocumentParagraphRun* run, RunRangeMap& runRanges, vint start, vint end, bool deepCopy)
			{
				CloneRunRecursivelyVisitor visitor(runRanges, start, end, deepCopy);
				run->Accept(&visitor);
				return visitor.clonedRun;
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_COLLECTSTYLE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;

/***********************************************************************
Search all used style names
***********************************************************************/

		namespace document_operation_visitors
		{
			class CollectStyleNameVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				List<WString>&					styleNames;

				CollectStyleNameVisitor(List<WString>& _styleNames)
					:styleNames(_styleNames)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					for (auto subRun : run->runs)
					{
						subRun->Accept(this);
					}
				}

				void Visit(DocumentTextRun* run)override
				{
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					if (!styleNames.Contains(run->styleName))
					{
						styleNames.Add(run->styleName);
					}
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					if (!styleNames.Contains(run->normalStyleName))
					{
						styleNames.Add(run->normalStyleName);
					}
					if (!styleNames.Contains(run->activeStyleName))
					{
						styleNames.Add(run->activeStyleName);
					}
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			void CollectStyleName(DocumentParagraphRun* run, List<WString>& styleNames)
			{
				CollectStyleNameVisitor visitor(styleNames);
				run->Accept(&visitor);
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_CUTRUN.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace document_editor;

/***********************************************************************
Cut all runs into pieces so that a run either completely outside or inside the specified range
If a run decides that itself should be cut, then leftRun and rightRun contains new run that will be inserted before and after it
***********************************************************************/

		namespace document_operation_visitors
		{
			class CutRunVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				RunRangeMap&					runRanges;
				vint							position;
				Ptr<DocumentRun>				leftRun;
				Ptr<DocumentRun>				rightRun;

				CutRunVisitor(RunRangeMap& _runRanges, vint _position)
					:runRanges(_runRanges)
					, position(_position)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					vint leftCount = 0;
					Ptr<DocumentRun> selectedRun;

					for (auto subRun : run->runs)
					{
						RunRange range = runRanges[subRun.Obj()];
						if (range.start<position)
						{
							leftCount++;
							if (position<range.end)
							{
								selectedRun = subRun;
							}
						}
						else
						{
							break;
						}
					}

					if (selectedRun)
					{
						selectedRun->Accept(this);
						if (leftRun && rightRun)
						{
							run->runs.RemoveAt(leftCount - 1);
							run->runs.Insert(leftCount - 1, leftRun);
							run->runs.Insert(leftCount, rightRun);
						}
					}

					Ptr<DocumentContainerRun> leftContainer = CopyRun(run).Cast<DocumentContainerRun>();
					Ptr<DocumentContainerRun> rightContainer = CopyRun(run).Cast<DocumentContainerRun>();
					// TODO: (enumerable) foreach
					for (vint i = 0; i<run->runs.Count(); i++)
					{
						(i<leftCount ? leftContainer : rightContainer)->runs.Add(run->runs[i]);
					}
					leftRun = leftContainer;
					rightRun = rightContainer;
				}

				void Visit(DocumentTextRun* run)override
				{
					RunRange range = runRanges[run];

					auto leftText = Ptr(new DocumentTextRun);
					leftText->text = run->text.Sub(0, position - range.start);

					auto rightText = Ptr(new DocumentTextRun);
					rightText->text = run->text.Sub(position - range.start, range.end - position);

					leftRun = leftText;
					rightRun = rightText;
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
					leftRun = 0;
					rightRun = 0;
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
					leftRun = 0;
					rightRun = 0;
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			void CutRun(DocumentParagraphRun* run, RunRangeMap& runRanges, vint position, Ptr<DocumentRun>& leftRun, Ptr<DocumentRun>& rightRun)
			{
				CutRunVisitor visitor(runRanges, position);
				run->Accept(&visitor);
				leftRun = visitor.leftRun;
				rightRun = visitor.rightRun;
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_GETRUNRANGE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;

/***********************************************************************
Calculate range informations for each run object
***********************************************************************/

		namespace document_operation_visitors
		{
			class GetRunRangeVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				RunRangeMap&					runRanges;
				vint							start;

				GetRunRangeVisitor(RunRangeMap& _runRanges)
					:runRanges(_runRanges)
					, start(0)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					RunRange range;
					range.start = start;
					for (auto subRun : run->runs)
					{
						subRun->Accept(this);
					}
					range.end = start;
					runRanges.Add(run, range);
				}

				void VisitContent(DocumentContentRun* run)
				{
					RunRange range;
					range.start = start;
					start += run->GetRepresentationText().Length();
					range.end = start;
					runRanges.Add(run, range);
				}

				void Visit(DocumentTextRun* run)override
				{
					VisitContent(run);
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
					VisitContent(run);
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
					VisitContent(run);
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			void GetRunRange(DocumentParagraphRun* run, RunRangeMap& runRanges)
			{
				GetRunRangeVisitor visitor(runRanges);
				run->Accept(&visitor);
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_LOCATEHYPERLINK.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;

/***********************************************************************
Get the hyperlink run that contains the specified position
***********************************************************************/

		namespace document_operation_visitors
		{
			class LocateHyperlinkVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				Ptr<DocumentHyperlinkRun::Package>	package;
				RunRangeMap&						runRanges;
				vint								start;
				vint								end;

				LocateHyperlinkVisitor(RunRangeMap& _runRanges, Ptr<DocumentHyperlinkRun::Package> _package, vint _start, vint _end)
					:runRanges(_runRanges)
					, package(_package)
					, start(_start)
					, end(_end)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					Ptr<DocumentRun> selectedRun;
					for (auto subRun : run->runs)
					{
						RunRange range = runRanges[subRun.Obj()];
						if (range.start <= start && end <= range.end)
						{
							subRun->Accept(this);
							break;
						}
					}
				}

				void Visit(DocumentTextRun* run)override
				{
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					package->hyperlinks.Add(Ptr(run));
				}

				void Visit(DocumentImageRun* run)override
				{
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			Ptr<DocumentHyperlinkRun::Package> LocateHyperlink(DocumentParagraphRun* run, RunRangeMap& runRanges, vint row, vint start, vint end)
			{
				auto package = Ptr(new DocumentHyperlinkRun::Package);
				package->row = row;
				{
					LocateHyperlinkVisitor visitor(runRanges, package, start, end);
					run->Accept(&visitor);
				}

				Ptr<DocumentHyperlinkRun> startRun, endRun;
				for (auto run : package->hyperlinks)
				{
					auto range = runRanges[run.Obj()];
					if (package->start == -1 || range.start < package->start)
					{
						package->start = range.start;
						startRun = run;
					}
					if (package->end == -1 || range.end > package->end)
					{
						package->end = range.end;
						endRun = run;
					}
				}

				while (startRun)
				{
					vint pos = runRanges[startRun.Obj()].start;
					if (pos == 0) break;

					auto newPackage = Ptr(new DocumentHyperlinkRun::Package);
					LocateHyperlinkVisitor visitor(runRanges, newPackage, pos - 1, pos);
					run->Accept(&visitor);
					if (newPackage->hyperlinks.Count() == 0) break;

					auto newRun = newPackage->hyperlinks[0];
					if (startRun->reference != newRun->reference) break;

					auto range = runRanges[newRun.Obj()];
					package->hyperlinks.Add(newRun);
					package->start = range.start;
					startRun = newRun;
				}

				vint length = runRanges[run].end;
				while (endRun)
				{
					vint pos = runRanges[endRun.Obj()].end;
					if (pos == length) break;

					auto newPackage = Ptr(new DocumentHyperlinkRun::Package);
					LocateHyperlinkVisitor visitor(runRanges, newPackage, pos, pos + 1);
					run->Accept(&visitor);
					if (newPackage->hyperlinks.Count() == 0) break;

					auto newRun = newPackage->hyperlinks[0];
					if (endRun->reference != newRun->reference) break;

					auto range = runRanges[newRun.Obj()];
					package->hyperlinks.Add(newRun);
					package->end = range.end;
					endRun = newRun;
				}

				return package;
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_LOCATESTYLE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;

/***********************************************************************
Get all container runs that contain the specified position from top to bottom
***********************************************************************/

		namespace document_operation_visitors
		{
			class LocateStyleVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				List<DocumentContainerRun*>&	locatedRuns;
				RunRangeMap&					runRanges;
				vint							position;
				bool							frontSide;

				LocateStyleVisitor(List<DocumentContainerRun*>& _locatedRuns, RunRangeMap& _runRanges, vint _position, bool _frontSide)
					:locatedRuns(_locatedRuns)
					, runRanges(_runRanges)
					, position(_position)
					, frontSide(_frontSide)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					locatedRuns.Add(run);
					Ptr<DocumentRun> selectedRun;
					for (auto subRun : run->runs)
					{
						RunRange range = runRanges[subRun.Obj()];
						if (position == range.start)
						{
							if (!frontSide)
							{
								selectedRun = subRun;
								break;
							}
						}
						else if (position == range.end)
						{
							if (frontSide)
							{
								selectedRun = subRun;
								break;
							}
						}
						else if (range.start<position && position<range.end)
						{
							selectedRun = subRun;
							break;
						}
					}

					if (selectedRun)
					{
						selectedRun->Accept(this);
					}
				}

				void Visit(DocumentTextRun* run)override
				{
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			void LocateStyle(DocumentParagraphRun* run, RunRangeMap& runRanges, vint position, bool frontSide, List<DocumentContainerRun*>& locatedRuns)
			{
				LocateStyleVisitor visitor(locatedRuns, runRanges, position, frontSide);
				run->Accept(&visitor);
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_REMOVECONTAINER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;

/***********************************************************************
Remove some containers that intersect with the specified range
If a run decides that itself should be removed, then replacedRuns contains all runs to replace itself
RemoveHyperlinkVisitor	: Remove all hyperlinks that intersect with the specified range
RemoveStyleNameVisitor	: Remove all style names that intersect with the specified range
ClearStyleVisitor		: Remove all styles that intersect with the specified range
***********************************************************************/

		namespace document_operation_visitors
		{
			class RemoveContainerVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				RunRangeMap&					runRanges;
				vint							start;
				vint							end;
				List<Ptr<DocumentRun>>			replacedRuns;

				RemoveContainerVisitor(RunRangeMap& _runRanges, vint _start, vint _end)
					:runRanges(_runRanges)
					, start(_start)
					, end(_end)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					// TODO: (enumerable) foreach:indexed(alterable(reversed))
					for (vint i = run->runs.Count() - 1; i >= 0; i--)
					{
						Ptr<DocumentRun> subRun = run->runs[i];
						RunRange range = runRanges[subRun.Obj()];
						if (range.start<end && start<range.end)
						{
							replacedRuns.Clear();
							subRun->Accept(this);
							if (replacedRuns.Count() != 1 || replacedRuns[0] != subRun)
							{
								run->runs.RemoveAt(i);
								// TODO: (enumerable) foreach
								for (vint j = 0; j<replacedRuns.Count(); j++)
								{
									run->runs.Insert(i + j, replacedRuns[j]);
								}
								i += replacedRuns.Count();
							}
						}
					}
					replacedRuns.Clear();
					replacedRuns.Add(Ptr(run));
				}

				void VisitContent(DocumentContentRun* run)
				{
					replacedRuns.Add(Ptr(run));
				}

				void RemoveContainer(DocumentContainerRun* run)
				{
					CopyFrom(replacedRuns, run->runs);
				}

				void Visit(DocumentTextRun* run)override
				{
					VisitContent(run);
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
					VisitContent(run);
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
					VisitContent(run);
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};

			class RemoveHyperlinkVisitor : public RemoveContainerVisitor
			{
			public:
				RemoveHyperlinkVisitor(RunRangeMap& _runRanges, vint _start, vint _end)
					:RemoveContainerVisitor(_runRanges, _start, _end)
				{
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					RemoveContainer(run);
				}
			};

			class RemoveStyleNameVisitor : public RemoveContainerVisitor
			{
			public:
				RemoveStyleNameVisitor(RunRangeMap& _runRanges, vint _start, vint _end)
					:RemoveContainerVisitor(_runRanges, _start, _end)
				{
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					RemoveContainer(run);
				}
			};

			class ClearStyleVisitor : public RemoveContainerVisitor
			{
			public:
				ClearStyleVisitor(RunRangeMap& _runRanges, vint _start, vint _end)
					:RemoveContainerVisitor(_runRanges, _start, _end)
				{
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					RemoveContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					RemoveContainer(run);
				}
			};

			class ConvertToPlainTextVisitor : public ClearStyleVisitor
			{
			public:
				ConvertToPlainTextVisitor(RunRangeMap& _runRanges, vint _start, vint _end)
					:ClearStyleVisitor(_runRanges, _start, _end)
				{
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					RemoveContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			void RemoveHyperlink(DocumentParagraphRun* run, RunRangeMap& runRanges, vint start, vint end)
			{
				RemoveHyperlinkVisitor visitor(runRanges, start, end);
				run->Accept(&visitor);
			}

			void RemoveStyleName(DocumentParagraphRun* run, RunRangeMap& runRanges, vint start, vint end)
			{
				RemoveStyleNameVisitor visitor(runRanges, start, end);
				run->Accept(&visitor);
			}

			void ClearStyle(DocumentParagraphRun* run, RunRangeMap& runRanges, vint start, vint end)
			{
				ClearStyleVisitor visitor(runRanges, start, end);
				run->Accept(&visitor);
			}

			void ConvertToPlainText(DocumentParagraphRun* run, RunRangeMap& runRanges, vint start, vint end)
			{
				ConvertToPlainTextVisitor visitor(runRanges, start, end);
				run->Accept(&visitor);
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_REMOVERUN.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;

/***********************************************************************
Remove text run contents with the specified range, or other content runs that intersect with the range
If a run decides that itself should be removed, then replacedRuns contains all runs to replace itself
***********************************************************************/

		namespace document_operation_visitors
		{
			class RemoveRunVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				RunRangeMap&					runRanges;
				vint							start;
				vint							end;
				List<Ptr<DocumentRun>>			replacedRuns;

				RemoveRunVisitor(RunRangeMap& _runRanges, vint _start, vint _end)
					:runRanges(_runRanges)
					, start(_start)
					, end(_end)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					if (start == end) return;
					// TODO: (enumerable) foreach:indexed(alterable(reversed))
					for (vint i = run->runs.Count() - 1; i >= 0; i--)
					{
						Ptr<DocumentRun> subRun = run->runs[i];
						RunRange range = runRanges[subRun.Obj()];

						vint maxStart = range.start > start ? range.start : start;
						vint minEnd = range.end < end ? range.end : end;
						if (maxStart < minEnd)
						{
							subRun->Accept(this);
							if (replacedRuns.Count() == 0 || subRun != replacedRuns[0])
							{
								run->runs.RemoveAt(i);
								// TODO: (enumerable) foreach
								for (vint j = 0; j<replacedRuns.Count(); j++)
								{
									run->runs.Insert(i + j, replacedRuns[j]);
								}
							}
						}
					}
					replacedRuns.Clear();
					replacedRuns.Add(Ptr(run));
				}

				void Visit(DocumentTextRun* run)override
				{
					replacedRuns.Clear();
					RunRange range = runRanges[run];

					if (start <= range.start)
					{
						if (end<range.end)
						{
							run->text = run->text.Sub(end - range.start, range.end - end);
							replacedRuns.Add(Ptr(run));
						}
					}
					else
					{
						if (end<range.end)
						{
							auto firstRun = Ptr(new DocumentTextRun);
							auto secondRun = Ptr(new DocumentTextRun);

							firstRun->text = run->text.Sub(0, start - range.start);
							secondRun->text = run->text.Sub(end - range.start, range.end - end);

							replacedRuns.Add(firstRun);
							replacedRuns.Add(secondRun);
						}
						else
						{
							run->text = run->text.Sub(0, start - range.start);
							replacedRuns.Add(Ptr(run));
						}
					}
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
					replacedRuns.Clear();
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
					replacedRuns.Clear();
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			void RemoveRun(DocumentParagraphRun* run, RunRangeMap& runRanges, vint start, vint end)
			{
				RemoveRunVisitor visitor(runRanges, start, end);
				run->Accept(&visitor);
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_REPLACESTYLENAME.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;

/***********************************************************************
Replace a style name with another one
***********************************************************************/

		namespace document_operation_visitors
		{
			class ReplaceStyleNameVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				WString							oldStyleName;
				WString							newStyleName;

				ReplaceStyleNameVisitor(const WString& _oldStyleName, const WString& _newStyleName)
					:oldStyleName(_oldStyleName)
					, newStyleName(_newStyleName)
				{
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					for (auto subRun : run->runs)
					{
						subRun->Accept(this);
					}
				}

				void Visit(DocumentTextRun* run)override
				{
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					if (run->styleName == oldStyleName) run->styleName = newStyleName;
					VisitContainer(run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					if (run->styleName == oldStyleName) run->styleName = newStyleName;
					if (run->normalStyleName == oldStyleName) run->normalStyleName = newStyleName;
					if (run->activeStyleName == oldStyleName) run->activeStyleName = newStyleName;
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			void ReplaceStyleName(DocumentParagraphRun* run, const WString& oldStyleName, const WString& newStyleName)
			{
				ReplaceStyleNameVisitor visitor(oldStyleName, newStyleName);
				run->Accept(&visitor);
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENTEDITOR_SUMMERIZESTYLE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;

		namespace document_operation_visitors
		{

/***********************************************************************
Calculate if all text in the specified range has some common styles
***********************************************************************/

			class SummarizeStyleVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				RunRangeMap&							runRanges;
				DocumentModel*							model;
				vint									start;
				vint									end;
				Ptr<DocumentStyleProperties>			style;
				List<DocumentModel::ResolvedStyle>		resolvedStyles;

				SummarizeStyleVisitor(RunRangeMap& _runRanges, DocumentModel* _model, vint _start, vint _end)
					:runRanges(_runRanges)
					, model(_model)
					, start(_start)
					, end(_end)
				{
					DocumentModel::ResolvedStyle resolvedStyle;
					resolvedStyle = model->GetStyle(DocumentModel::DefaultStyleName, resolvedStyle);
					resolvedStyles.Add(resolvedStyle);
				}

				const DocumentModel::ResolvedStyle& GetCurrentResolvedStyle()
				{
					return resolvedStyles[resolvedStyles.Count() - 1];
				}

				// ---------------------------------------------------------

				template<typename T>
				void SetStyleItem(Nullable<T> DocumentStyleProperties::* dstField, T FontProperties::* srcField)
				{
					const DocumentModel::ResolvedStyle& src = GetCurrentResolvedStyle();
					if (style.Obj()->*dstField && (style.Obj()->*dstField).Value() != src.style.*srcField)
					{
						style.Obj()->*dstField = Nullable<T>();
					}
				}

				template<typename T>
				void SetStyleItem(Nullable<T> DocumentStyleProperties::* dstField, T DocumentModel::ResolvedStyle::* srcField)
				{
					const DocumentModel::ResolvedStyle& src = GetCurrentResolvedStyle();
					if (style.Obj()->*dstField && (style.Obj()->*dstField).Value() != src.*srcField)
					{
						style.Obj()->*dstField = Nullable<T>();
					}
				}

				void SetStyleItem(Nullable<DocumentFontSize> DocumentStyleProperties::* dstField, vint FontProperties::* srcField)
				{
					const DocumentModel::ResolvedStyle& src = GetCurrentResolvedStyle();
					if (style.Obj()->*dstField)
					{
						auto dfs = (style.Obj()->*dstField).Value();
						if (dfs.relative || dfs.size != src.style.*srcField)
						{
							style.Obj()->*dstField = Nullable<DocumentFontSize>();
						}
					}
				}

				// ---------------------------------------------------------

				template<typename T>
				void OverrideStyleItem(Nullable<T> DocumentStyleProperties::* dstField, T FontProperties::* srcField)
				{
					const DocumentModel::ResolvedStyle& src = GetCurrentResolvedStyle();
					style.Obj()->*dstField = src.style.*srcField;
				}

				template<typename T>
				void OverrideStyleItem(Nullable<T> DocumentStyleProperties::* dstField, T DocumentModel::ResolvedStyle::* srcField)
				{
					const DocumentModel::ResolvedStyle& src = GetCurrentResolvedStyle();
					style.Obj()->*dstField = src.*srcField;
				}

				void OverrideStyleItem(Nullable<DocumentFontSize> DocumentStyleProperties::* dstField, vint FontProperties::* srcField)
				{
					const DocumentModel::ResolvedStyle& src = GetCurrentResolvedStyle();
					style.Obj()->*dstField = DocumentFontSize((double)(src.style.*srcField), false);
				}

				// ---------------------------------------------------------

				void VisitContainer(DocumentContainerRun* run)
				{
					// TODO: (enumerable) foreach:reversed
					for (vint i = run->runs.Count() - 1; i >= 0; i--)
					{
						Ptr<DocumentRun> subRun = run->runs[i];
						RunRange range = runRanges[subRun.Obj()];
						if (range.start<end && start<range.end)
						{
							subRun->Accept(this);
						}
					}
				}

				void Visit(DocumentTextRun* run)override
				{
					const DocumentModel::ResolvedStyle& currentResolvedStyle = GetCurrentResolvedStyle();
					if (style)
					{
						SetStyleItem(&DocumentStyleProperties::face, &FontProperties::fontFamily);
						SetStyleItem(&DocumentStyleProperties::size, &FontProperties::size);
						SetStyleItem(&DocumentStyleProperties::color, &DocumentModel::ResolvedStyle::color);
						SetStyleItem(&DocumentStyleProperties::backgroundColor, &DocumentModel::ResolvedStyle::backgroundColor);
						SetStyleItem(&DocumentStyleProperties::bold, &FontProperties::bold);
						SetStyleItem(&DocumentStyleProperties::italic, &FontProperties::italic);
						SetStyleItem(&DocumentStyleProperties::underline, &FontProperties::underline);
						SetStyleItem(&DocumentStyleProperties::strikeline, &FontProperties::strikeline);
						SetStyleItem(&DocumentStyleProperties::antialias, &FontProperties::antialias);
						SetStyleItem(&DocumentStyleProperties::verticalAntialias, &FontProperties::verticalAntialias);
					}
					else
					{
						style = Ptr(new DocumentStyleProperties);
						OverrideStyleItem(&DocumentStyleProperties::face, &FontProperties::fontFamily);
						OverrideStyleItem(&DocumentStyleProperties::size, &FontProperties::size);
						OverrideStyleItem(&DocumentStyleProperties::color, &DocumentModel::ResolvedStyle::color);
						OverrideStyleItem(&DocumentStyleProperties::backgroundColor, &DocumentModel::ResolvedStyle::backgroundColor);
						OverrideStyleItem(&DocumentStyleProperties::bold, &FontProperties::bold);
						OverrideStyleItem(&DocumentStyleProperties::italic, &FontProperties::italic);
						OverrideStyleItem(&DocumentStyleProperties::underline, &FontProperties::underline);
						OverrideStyleItem(&DocumentStyleProperties::strikeline, &FontProperties::strikeline);
						OverrideStyleItem(&DocumentStyleProperties::antialias, &FontProperties::antialias);
						OverrideStyleItem(&DocumentStyleProperties::verticalAntialias, &FontProperties::verticalAntialias);
					}
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					const DocumentModel::ResolvedStyle& currentResolvedStyle = GetCurrentResolvedStyle();
					DocumentModel::ResolvedStyle resolvedStyle = model->GetStyle(run->style, currentResolvedStyle);
					resolvedStyles.Add(resolvedStyle);
					VisitContainer(run);
					resolvedStyles.RemoveAt(resolvedStyles.Count() - 1);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					const DocumentModel::ResolvedStyle& currentResolvedStyle = GetCurrentResolvedStyle();
					DocumentModel::ResolvedStyle resolvedStyle = model->GetStyle(run->styleName, currentResolvedStyle);
					resolvedStyles.Add(resolvedStyle);
					VisitContainer(run);
					resolvedStyles.RemoveAt(resolvedStyles.Count() - 1);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					const DocumentModel::ResolvedStyle& currentResolvedStyle = GetCurrentResolvedStyle();
					DocumentModel::ResolvedStyle resolvedStyle = model->GetStyle(run->styleName, currentResolvedStyle);
					resolvedStyles.Add(resolvedStyle);
					VisitContainer(run);
					resolvedStyles.RemoveAt(resolvedStyles.Count() - 1);
				}

				void Visit(DocumentImageRun* run)override
				{
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};

/***********************************************************************
Calculate if all text in the specified range has a common style name
***********************************************************************/

			class SummarizeStyleNameVisitor : public Object, public DocumentRun::IVisitor
			{
			public:
				RunRangeMap&							runRanges;
				DocumentModel*							model;
				vint									start;
				vint									end;
				Nullable<WString>						currentStyleName;
				Nullable<WString>						styleName;
				bool									assignedStyleName = false;

				SummarizeStyleNameVisitor(RunRangeMap& _runRanges, DocumentModel* _model, vint _start, vint _end)
					:runRanges(_runRanges)
					, model(_model)
					, start(_start)
					, end(_end)
				{
				}

				void VisitContentRun(DocumentContentRun* run)
				{
					if (!assignedStyleName)
					{
						styleName = currentStyleName;
						assignedStyleName = true;
					}
					else if (styleName && (!currentStyleName || styleName.Value() != currentStyleName.Value()))
					{
						styleName = Nullable<WString>();
					}
				}

				void VisitContainer(DocumentContainerRun* run)
				{
					// TODO: (enumerable) foreach:reversed
					for (vint i = run->runs.Count() - 1; i >= 0; i--)
					{
						Ptr<DocumentRun> subRun = run->runs[i];
						RunRange range = runRanges[subRun.Obj()];
						if (range.start<end && start<range.end)
						{
							subRun->Accept(this);
						}
					}
				}

				void Visit(DocumentTextRun* run)override
				{
					VisitContentRun(run);
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					auto oldStyleName = currentStyleName;
					currentStyleName = run->styleName;
					VisitContainer(run);
					currentStyleName = oldStyleName;
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					VisitContainer(run);
				}

				void Visit(DocumentImageRun* run)override
				{
					VisitContentRun(run);
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
					VisitContentRun(run);
				}

				void Visit(DocumentParagraphRun* run)override
				{
					VisitContainer(run);
				}
			};
		}
		using namespace document_operation_visitors;

		namespace document_editor
		{
			Ptr<DocumentStyleProperties> SummarizeStyle(DocumentParagraphRun* run, RunRangeMap& runRanges, DocumentModel* model, vint start, vint end)
			{
				SummarizeStyleVisitor visitor(runRanges, model, start, end);
				run->Accept(&visitor);
				return visitor.style;
			}

			Nullable<WString> SummarizeStyleName(DocumentParagraphRun* run, RunRangeMap& runRanges, DocumentModel* model, vint start, vint end)
			{
				SummarizeStyleNameVisitor visitor(runRanges, model, start, end);
				run->Accept(&visitor);
				return visitor.styleName;
			}

			template<typename T>
			void AggregateStyleItem(Ptr<DocumentStyleProperties>& dst, Ptr<DocumentStyleProperties> src, Nullable<T> DocumentStyleProperties::* field)
			{
				if (dst.Obj()->*field && (!(src.Obj()->*field) || (dst.Obj()->*field).Value() != (src.Obj()->*field).Value()))
				{
					dst.Obj()->*field = Nullable<T>();
				}
			}

			void AggregateStyle(Ptr<DocumentStyleProperties>& dst, Ptr<DocumentStyleProperties> src)
			{
				AggregateStyleItem(dst, src, &DocumentStyleProperties::face);
				AggregateStyleItem(dst, src, &DocumentStyleProperties::size);
				AggregateStyleItem(dst, src, &DocumentStyleProperties::color);
				AggregateStyleItem(dst, src, &DocumentStyleProperties::backgroundColor);
				AggregateStyleItem(dst, src, &DocumentStyleProperties::bold);
				AggregateStyleItem(dst, src, &DocumentStyleProperties::italic);
				AggregateStyleItem(dst, src, &DocumentStyleProperties::underline);
				AggregateStyleItem(dst, src, &DocumentStyleProperties::strikeline);
				AggregateStyleItem(dst, src, &DocumentStyleProperties::antialias);
				AggregateStyleItem(dst, src, &DocumentStyleProperties::verticalAntialias);
			}
		}
	}
}


/***********************************************************************
.\RESOURCES\GUIDOCUMENT_EDIT.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace document_editor;

/***********************************************************************
DocumentModel::EditRangeOperations
***********************************************************************/

		bool DocumentModel::CheckEditRange(TextPos begin, TextPos end, RunRangeMap& relatedRanges)
		{
			// check caret range
			if(begin>end) return false;
			if(begin.row<0 || begin.row>=paragraphs.Count()) return false;
			if(end.row<0 || end.row>=paragraphs.Count()) return false;

			// determine run ranges
			GetRunRange(paragraphs[begin.row].Obj(), relatedRanges);
			if(begin.row!=end.row)
			{
				GetRunRange(paragraphs[end.row].Obj(), relatedRanges);
			}
			
			// check caret range
			RunRange beginRange=relatedRanges[paragraphs[begin.row].Obj()];
			RunRange endRange=relatedRanges[paragraphs[end.row].Obj()];
			if(begin.column<0 || begin.column>beginRange.end) return false;
			if(end.column<0 || end.column>endRange.end) return false;

			return true;
		}

		Ptr<DocumentModel> DocumentModel::CopyDocument(TextPos begin, TextPos end, bool deepCopy)
		{
			auto newDocument = Ptr(new DocumentModel);

			if (begin != end || paragraphs.Count() > 0)
			{
				// check caret range
				RunRangeMap runRanges;
				if (!CheckEditRange(begin, end, runRanges)) return nullptr;

				// get ranges
				for (vint i = begin.row + 1; i < end.row; i++)
				{
					GetRunRange(paragraphs[i].Obj(), runRanges);
				}

				// copy paragraphs
				if (begin.row == end.row)
				{
					newDocument->paragraphs.Add(CopyRunRecursively(paragraphs[begin.row].Obj(), runRanges, begin.column, end.column, deepCopy).Cast<DocumentParagraphRun>());
				}
				else
				{
					for (vint i = begin.row; i <= end.row; i++)
					{
						Ptr<DocumentParagraphRun> paragraph = paragraphs[i];
						RunRange range = runRanges[paragraph.Obj()];
						if (i == begin.row)
						{
							newDocument->paragraphs.Add(CopyRunRecursively(paragraph.Obj(), runRanges, begin.column, range.end, deepCopy).Cast<DocumentParagraphRun>());
						}
						else if (i == end.row)
						{
							newDocument->paragraphs.Add(CopyRunRecursively(paragraph.Obj(), runRanges, range.start, end.column, deepCopy).Cast<DocumentParagraphRun>());
						}
						else if (deepCopy)
						{
							newDocument->paragraphs.Add(CopyRunRecursively(paragraph.Obj(), runRanges, range.start, range.end, deepCopy).Cast<DocumentParagraphRun>());
						}
						else
						{
							newDocument->paragraphs.Add(paragraph);
						}
					}
				}
			}

			// copy styles
			List<WString> styleNames;
			for (auto paragraph : newDocument->paragraphs)
			{
				CollectStyleName(paragraph.Obj(), styleNames);
			}

			// TODO: (enumerable) foreach:alterable
			for(vint i=0;i<styleNames.Count();i++)
			{
				WString styleName=styleNames[i];
				if(!newDocument->styles.Keys().Contains(styleName))
				{
					if (!styles.Keys().Contains(styleName))
					{
						continue;
					}
					Ptr<DocumentStyle> style=styles[styleName];
					if(deepCopy)
					{
						auto newStyle = Ptr(new DocumentStyle);
						newStyle->parentStyleName=style->parentStyleName;
						newStyle->styles=CopyStyle(style->styles);
						newStyle->resolvedStyles=CopyStyle(style->resolvedStyles);
						newDocument->styles.Add(styleName, newStyle);
					}
					else
					{
						newDocument->styles.Add(styleName, style);
					}

					if(!styleNames.Contains(style->parentStyleName) && style->parentStyleName != WString::Empty)
					{
						styleNames.Add(style->parentStyleName);
					}
				}
			}

			return newDocument;
		}

		Ptr<DocumentModel> DocumentModel::CopyDocument()
		{
			if (paragraphs.Count() == 0)
			{
				return CopyDocument({ 0,0 }, { 0,0 }, true);
			}
			else
			{
				// determine run ranges
				RunRangeMap runRanges;
				vint lastParagraphIndex = paragraphs.Count() - 1;
				GetRunRange(paragraphs[lastParagraphIndex].Obj(), runRanges);

				TextPos begin(0, 0);
				TextPos end(lastParagraphIndex, runRanges[paragraphs[lastParagraphIndex].Obj()].end);
				return CopyDocument(begin, end, true);
			}
		}

		bool DocumentModel::CutParagraph(TextPos position)
		{
			if(position.row<0 || position.row>=paragraphs.Count()) return false;

			Ptr<DocumentParagraphRun> paragraph=paragraphs[position.row];
			RunRangeMap runRanges;
			Ptr<DocumentRun> leftRun, rightRun;

			GetRunRange(paragraph.Obj(), runRanges);
			CutRun(paragraph.Obj(), runRanges, position.column, leftRun, rightRun);

			CopyFrom(paragraph->runs, leftRun.Cast<DocumentParagraphRun>()->runs);
			CopyFrom(paragraph->runs, rightRun.Cast<DocumentParagraphRun>()->runs, true);
			
			return true;
		}

		bool DocumentModel::CutEditRange(TextPos begin, TextPos end)
		{
			// check caret range
			if(begin>end) return false;
			if(begin.row<0 || begin.row>=paragraphs.Count()) return false;
			if(end.row<0 || end.row>=paragraphs.Count()) return false;

			// cut paragraphs
			CutParagraph(begin);
			if(begin!=end)
			{
				CutParagraph(end);
			}
			return true;
		}

		bool DocumentModel::EditContainer(TextPos begin, TextPos end, const Func<void(DocumentParagraphRun*, RunRangeMap&, vint, vint)>& editor)
		{
			if(begin==end) return false;

			// cut paragraphs
			if(!CutEditRange(begin, end)) return false;

			// check caret range
			RunRangeMap runRanges;
			if(!CheckEditRange(begin, end, runRanges)) return false;

			// edit container
			if(begin.row==end.row)
			{
				editor(paragraphs[begin.row].Obj(), runRanges, begin.column, end.column);
			}
			else
			{
				for(vint i=begin.row;i<=end.row;i++)
				{
					Ptr<DocumentParagraphRun> paragraph=paragraphs[i];
					if(begin.row<i && i<end.row)
					{
						GetRunRange(paragraph.Obj(), runRanges);
					}
					RunRange range=runRanges[paragraph.Obj()];
					if(i==begin.row)
					{
						editor(paragraph.Obj(), runRanges, begin.column, range.end);
					}
					else if(i==end.row)
					{
						editor(paragraph.Obj(), runRanges, range.start, end.column);
					}
					else
					{
						editor(paragraph.Obj(), runRanges, range.start, range.end);
					}
				}
			}

			// clear paragraphs
			for(vint i=begin.row;i<=end.row;i++)
			{
				ClearUnnecessaryRun(paragraphs[i].Obj(), this);
			}

			return true;
		}

/***********************************************************************
DocumentModel::EditRun
***********************************************************************/

		vint DocumentModel::EditRun(TextPos begin, TextPos end, Ptr<DocumentModel> replaceToModel, bool copy)
		{
			// check caret range
			RunRangeMap runRanges;
			if(!CheckEditRange(begin, end, runRanges)) return -1;

			auto model = replaceToModel;
			if (copy)
			{
				model = replaceToModel->CopyDocument();
			}

			// calculate new names for the model's styles to prevent conflicting
			List<WString> oldNames, newNames;
			CopyFrom(oldNames, model->styles.Keys());
			CopyFrom(newNames, model->styles.Keys());
			// TODO: (enumerable) foreach:indexed(allow-set)
			for(vint i=0;i<newNames.Count();i++)
			{
				WString name=newNames[i];
				if((name.Length()==0 || name[0]!=L'#') && styles.Keys().Contains(name))
				{
					auto existingStyle = styles[name];
					auto incomingStyle = model->styles[name];
					if (existingStyle->parentStyleName == incomingStyle->parentStyleName
						&& document_editor::CompareStyleProperties(existingStyle->styles, incomingStyle->styles))
					{
						continue;
					}
					vint index=2;
					while(true)
					{
						WString newName=name+L"_"+itow(index++);
						if(!styles.Keys().Contains(newName) && !model->styles.Keys().Contains(newName))
						{
							newNames[i]=newName;
							break;
						}
					}
				}
			}

			// rename model's styles
			typedef Pair<WString, WString> NamePair;
			for (auto name : From(oldNames).Pairwise(newNames))
			{
				model->RenameStyle(name.key, name.value);
			}
			for (auto name : newNames)
			{
				if((name.Length()==0 || name[0]!=L'#') && !styles.Keys().Contains(name))
				{
					styles.Add(name, model->styles[name]);
				}
			}

			// edit runs
			Array<Ptr<DocumentParagraphRun>> runs;
			CopyFrom(runs, model->paragraphs);
			return EditRunNoCopy(begin, end, runs);
		}

		vint DocumentModel::EditRunNoCopy(TextPos begin, TextPos end, const collections::Array<Ptr<DocumentParagraphRun>>& runs)
		{
			// check caret range
			RunRangeMap runRanges;
			if(!CheckEditRange(begin, end, runRanges)) return -1;

			// remove unnecessary paragraphs
			if(begin.row!=end.row)
			{
				for(vint i=end.row-1;i>begin.row;i--)
				{
					paragraphs.RemoveAt(i);
				}
				end.row=begin.row+1;
			}

			// remove unnecessary runs and ensure begin.row!=end.row
			if(begin.row==end.row)
			{
				RemoveRun(paragraphs[begin.row].Obj(), runRanges, begin.column, end.column);

				Ptr<DocumentRun> leftRun, rightRun;
				runRanges.Clear();
				GetRunRange(paragraphs[begin.row].Obj(), runRanges);
				CutRun(paragraphs[begin.row].Obj(), runRanges, begin.column, leftRun, rightRun);

				paragraphs.RemoveAt(begin.row);
				paragraphs.Insert(begin.row, leftRun.Cast<DocumentParagraphRun>());
				paragraphs.Insert(begin.row+1, rightRun.Cast<DocumentParagraphRun>());
				end.row=begin.row+1;
			}
			else
			{
				RemoveRun(paragraphs[begin.row].Obj(), runRanges, begin.column, runRanges[paragraphs[begin.row].Obj()].end);
				RemoveRun(paragraphs[end.row].Obj(), runRanges, 0, end.column);
			}

			// insert new paragraphs
			Ptr<DocumentParagraphRun> beginParagraph=paragraphs[begin.row];
			Ptr<DocumentParagraphRun> endParagraph=paragraphs[end.row];
			if(runs.Count()==0)
			{
				CopyFrom(beginParagraph->runs, endParagraph->runs, true);
				paragraphs.RemoveAt(end.row);
			}
			else if(runs.Count()==1)
			{
				CopyFrom(beginParagraph->runs, runs[0]->runs, true);
				CopyFrom(beginParagraph->runs, endParagraph->runs, true);
				paragraphs.RemoveAt(end.row);
			}
			else
			{
				Ptr<DocumentParagraphRun> newBeginRuns=runs[0];
				CopyFrom(beginParagraph->runs, newBeginRuns->runs, true);
				
				Ptr<DocumentParagraphRun> newEndRuns=runs[runs.Count()-1];
				if (newEndRuns->alignment)
				{
					endParagraph->alignment = newEndRuns->alignment;
				}

				// TODO: (enumerable) foreach
				for(vint i=0;i<newEndRuns->runs.Count();i++)
				{
					endParagraph->runs.Insert(i, newEndRuns->runs[i]);
				}

				// TODO: (enumerable) foreach:indexed
				for(vint i=1;i<runs.Count()-1;i++)
				{
					paragraphs.Insert(begin.row+i, runs[i]);
				}
			}

			// clear unnecessary runs
			vint rows=runs.Count()==0?1:runs.Count();
			for(vint i=0;i<rows;i++)
			{
				ClearUnnecessaryRun(paragraphs[begin.row+i].Obj(), this);
			}
			return rows;
		}

/***********************************************************************
DocumentModel::EditText
***********************************************************************/

		vint DocumentModel::EditText(TextPos begin, TextPos end, bool frontSide, const collections::Array<WString>& text)
		{
			// check caret range
			RunRangeMap runRanges;
			if(!CheckEditRange(begin, end, runRanges)) return -1;

			// calcuate the position to get the text style
			TextPos stylePosition;
			if(frontSide)
			{
				stylePosition=begin;
				if(stylePosition.column==0)
				{
					frontSide=false;
				}
			}
			else
			{
				stylePosition=end;
				if(stylePosition.column==runRanges[paragraphs[end.row].Obj()].end)
				{
					frontSide=true;
				}
			}

			// copy runs that contains the target style for new text
			List<DocumentContainerRun*> styleRuns;
			LocateStyle(paragraphs[stylePosition.row].Obj(), runRanges, stylePosition.column, frontSide, styleRuns);

			// create paragraphs
			Array<Ptr<DocumentParagraphRun>> runs(text.Count());
			// TODO: (enumerable) foreach:indexed
			for(vint i=0;i<text.Count();i++)
			{
				Ptr<DocumentRun> paragraph=CopyStyledText(styleRuns, text[i]);
				runs[i]=paragraph.Cast<DocumentParagraphRun>();
			}

			// replace the paragraphs
			return EditRunNoCopy(begin, end, runs);
		}

/***********************************************************************
DocumentModel::EditStyle
***********************************************************************/

		bool DocumentModel::EditStyle(TextPos begin, TextPos end, Ptr<DocumentStyleProperties> style)
		{
			return EditContainer(begin, end, [=](DocumentParagraphRun* paragraph, RunRangeMap& runRanges, vint start, vint end)
			{
				AddStyle(paragraph, runRanges, start, end, style);
			});
		}

/***********************************************************************
DocumentModel::EditImage
***********************************************************************/

		Ptr<DocumentImageRun> DocumentModel::EditImage(TextPos begin, TextPos end, Ptr<GuiImageData> image)
		{
			auto imageRun = Ptr(new DocumentImageRun);
			imageRun->image=image->GetImage();
			imageRun->frameIndex=image->GetFrameIndex();

			auto paragraph = Ptr(new DocumentParagraphRun);
			paragraph->runs.Add(imageRun);

			Array<Ptr<DocumentParagraphRun>> runs(1);
			runs[0]=paragraph;
			if(EditRunNoCopy(begin, end, runs))
			{
				return imageRun;
			}
			else
			{
				return 0;
			}
		}

/***********************************************************************
DocumentModel::EditHyperlink
***********************************************************************/

		bool DocumentModel::EditHyperlink(vint paragraphIndex, vint begin, vint end, const WString& reference, const WString& normalStyleName, const WString& activeStyleName)
		{
			auto package = GetHyperlink(paragraphIndex, begin, end);
			if (package->hyperlinks.Count() > 0)
			{
				for (auto run : package->hyperlinks)
				{
					run->reference = reference;
					run->normalStyleName = normalStyleName;
					run->activeStyleName = activeStyleName;
					run->styleName = normalStyleName;
				}
				return true;
			}
			else if (RemoveHyperlink(paragraphIndex, begin, end))
			{
				CutEditRange(TextPos(paragraphIndex, begin), TextPos(paragraphIndex, end));

				RunRangeMap runRanges;
				Ptr<DocumentParagraphRun> paragraph = paragraphs[paragraphIndex];
				GetRunRange(paragraph.Obj(), runRanges);
				AddHyperlink(paragraph.Obj(), runRanges, begin, end, reference, normalStyleName, activeStyleName);

				ClearUnnecessaryRun(paragraph.Obj(), this);
				return true;
			}
			return false;
		}

		bool DocumentModel::RemoveHyperlink(vint paragraphIndex, vint begin, vint end)
		{
			RunRangeMap runRanges;
			if (!CheckEditRange(TextPos(paragraphIndex, begin), TextPos(paragraphIndex, end), runRanges)) return 0;

			auto paragraph = paragraphs[paragraphIndex];
			auto package = LocateHyperlink(paragraph.Obj(), runRanges, paragraphIndex, begin, end);
			document_editor::RemoveHyperlink(paragraph.Obj(), runRanges, package->start, package->end);
			ClearUnnecessaryRun(paragraph.Obj(), this);
			return true;
		}

		Ptr<DocumentHyperlinkRun::Package> DocumentModel::GetHyperlink(vint paragraphIndex, vint begin, vint end)
		{
			RunRangeMap runRanges;
			if (!CheckEditRange(TextPos(paragraphIndex, begin), TextPos(paragraphIndex, end), runRanges)) return 0;

			auto paragraph = paragraphs[paragraphIndex];
			return LocateHyperlink(paragraph.Obj(), runRanges, paragraphIndex, begin, end);
		}

/***********************************************************************
DocumentModel::EditStyleName
***********************************************************************/

		bool DocumentModel::EditStyleName(TextPos begin, TextPos end, const WString& styleName)
		{
			return EditContainer(begin, end, [=](DocumentParagraphRun* paragraph, RunRangeMap& runRanges, vint start, vint end)
			{
				AddStyleName(paragraph, runRanges, start, end, styleName);
			});
		}

		bool DocumentModel::RemoveStyleName(TextPos begin, TextPos end)
		{
			return EditContainer(begin, end, [=](DocumentParagraphRun* paragraph, RunRangeMap& runRanges, vint start, vint end)
			{
				document_editor::RemoveStyleName(paragraph, runRanges, start, end);
			});
		}

		bool DocumentModel::RenameStyle(const WString& oldStyleName, const WString& newStyleName)
		{
			vint index=styles.Keys().IndexOf(oldStyleName);
			if(index==-1) return false;
			if(styles.Keys().Contains(newStyleName)) return false;

			Ptr<DocumentStyle> style=styles.Values()[index];
			styles.Remove(oldStyleName);
			styles.Add(newStyleName, style);

			for (auto subStyle : styles.Values())
			{
				if(subStyle->parentStyleName==oldStyleName)
				{
					subStyle->parentStyleName=newStyleName;
				}
			}

			for (auto paragraph : paragraphs)
			{
				ReplaceStyleName(paragraph.Obj(), oldStyleName, newStyleName);
			}
			return true;
		}

/***********************************************************************
DocumentModel::ClearStyle
***********************************************************************/

		bool DocumentModel::ClearStyle(TextPos begin, TextPos end)
		{
			return EditContainer(begin, end, [=](DocumentParagraphRun* paragraph, RunRangeMap& runRanges, vint start, vint end)
			{
				document_editor::ClearStyle(paragraph, runRanges, start, end);
			});
		}

/***********************************************************************
DocumentModel::ConvertToPlainText
***********************************************************************/

		bool DocumentModel::ConvertToPlainText(TextPos begin, TextPos end)
		{
			return EditContainer(begin, end, [=](DocumentParagraphRun* paragraph, RunRangeMap& runRanges, vint start, vint end)
			{
				document_editor::ConvertToPlainText(paragraph, runRanges, start, end);
			});
		}

/***********************************************************************
DocumentModel::Summarize
***********************************************************************/

		Ptr<DocumentStyleProperties> DocumentModel::SummarizeStyle(TextPos begin, TextPos end)
		{
			Ptr<DocumentStyleProperties> style;
			RunRangeMap runRanges;

			if (begin == end) goto END_OF_SUMMERIZING;

			// check caret range
			if (!CheckEditRange(begin, end, runRanges)) return nullptr;

			// Summarize container
			if (begin.row == end.row)
			{
				style = document_editor::SummarizeStyle(paragraphs[begin.row].Obj(), runRanges, this, begin.column, end.column);
			}
			else
			{
				for (vint i = begin.row; i <= end.row; i++)
				{
					Ptr<DocumentParagraphRun> paragraph = paragraphs[i];
					if (begin.row < i && i < end.row)
					{
						GetRunRange(paragraph.Obj(), runRanges);
					}
					RunRange range = runRanges[paragraph.Obj()];
					Ptr<DocumentStyleProperties> paragraphStyle;
					if (i == begin.row)
					{
						paragraphStyle = document_editor::SummarizeStyle(paragraph.Obj(), runRanges, this, begin.column, range.end);
					}
					else if (i == end.row)
					{
						paragraphStyle = document_editor::SummarizeStyle(paragraph.Obj(), runRanges, this, range.start, end.column);
					}
					else
					{
						paragraphStyle = document_editor::SummarizeStyle(paragraph.Obj(), runRanges, this, range.start, range.end);
					}

					if (!style)
					{
						style = paragraphStyle;
					}
					else if (paragraphStyle)
					{
						AggregateStyle(style, paragraphStyle);
					}
				}
			}

		END_OF_SUMMERIZING:
			if (!style)
			{
				style = Ptr(new DocumentStyleProperties);
			}
			return style;
		}

		Nullable<WString> DocumentModel::SummarizeStyleName(TextPos begin, TextPos end)
		{
			if (begin == end) return {};

			// check caret range
			RunRangeMap runRanges;
			if (!CheckEditRange(begin, end, runRanges)) return {};

			// Summarize container
			Nullable<WString> styleName;

			if (begin.row == end.row)
			{
				styleName = document_editor::SummarizeStyleName(paragraphs[begin.row].Obj(), runRanges, this, begin.column, end.column);
			}
			else
			{
				for (vint i = begin.row; i <= end.row; i++)
				{
					Ptr<DocumentParagraphRun> paragraph = paragraphs[i];
					if (begin.row < i && i < end.row)
					{
						GetRunRange(paragraph.Obj(), runRanges);
					}
					RunRange range = runRanges[paragraph.Obj()];
					Nullable<WString> newStyleName;
					if (i == begin.row)
					{
						newStyleName = document_editor::SummarizeStyleName(paragraph.Obj(), runRanges, this, begin.column, range.end);
					}
					else if (i == end.row)
					{
						newStyleName = document_editor::SummarizeStyleName(paragraph.Obj(), runRanges, this, range.start, end.column);
					}
					else
					{
						newStyleName = document_editor::SummarizeStyleName(paragraph.Obj(), runRanges, this, range.start, end.column);
					}

					if (i == begin.row)
					{
						styleName = newStyleName;
					}
					else if (!styleName || !newStyleName || styleName.Value() != newStyleName.Value())
					{
						styleName = Nullable<WString>();
					}
				}
			}
			return styleName;
		}

		Nullable<Alignment> DocumentModel::SummarizeParagraphAlignment(TextPos begin, TextPos end)
		{
			bool left = false;
			bool center = false;
			bool right = false;

			RunRangeMap runRanges;
			if (!CheckEditRange(begin, end, runRanges)) return {};

			for (vint i = begin.row; i <= end.row; i++)
			{
				auto paragraph = paragraphs[i];
				if (paragraph->alignment)
				{
					switch (paragraph->alignment.Value())
					{
					case Alignment::Left:
						left = true;
						break;
					case Alignment::Center:
						center = true;
						break;
					case Alignment::Right:
						right = true;
						break;
					}
				}
				else
				{
					left = true;
				}
			}

			if (left && !center && !right) return Alignment::Left;
			if (!left && center && !right) return Alignment::Center;
			if (!left && !center && right) return Alignment::Right;
			return {};
		}
	}
}


/***********************************************************************
.\RESOURCES\GUIDOCUMENT_LOAD.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace glr::xml;
		using namespace regex;

/***********************************************************************
document_operation_visitors::DeserializeNodeVisitor
***********************************************************************/

		namespace document_operation_visitors
		{
			class DeserializeNodeVisitor : public XmlNode::IVisitor
			{
			public:
				Ptr<DocumentModel>					model;
				Ptr<DocumentContainerRun>			container;
				vint								paragraphIndex;
				Ptr<GuiResourceItem>				resource;
				Ptr<GuiResourcePathResolver>		resolver;
				Regex								regexAttributeApply;
				GuiResourceError::List&				errors;

				DeserializeNodeVisitor(Ptr<DocumentModel> _model, Ptr<DocumentParagraphRun> _paragraph, vint _paragraphIndex, Ptr<GuiResourceItem> _resource, Ptr<GuiResourcePathResolver> _resolver, GuiResourceError::List& _errors)
					:model(_model)
					, container(_paragraph)
					, paragraphIndex(_paragraphIndex)
					, resource(_resource)
					, resolver(_resolver)
					, regexAttributeApply(L"/{@(<value>[^{}]+)/}")
					, errors(_errors)
				{
				}

				void PrintText(const WString& text)
				{
					auto run = Ptr(new DocumentTextRun);
					run->text = text;
					container->runs.Add(run);
				}

				void Visit(XmlText* node)override
				{
					PrintText(node->content.value);
				}

				void Visit(XmlCData* node)override
				{
					PrintText(node->content.value);
				}

				void Visit(XmlComment* node)override
				{
				}

				void Visit(XmlElement* node)override
				{
					Ptr<DocumentContainerRun> createdContainer;
					bool useTemplateInfo = false;
					XmlElement* subNodeContainer = node;

					if (node->name.value == L"br")
					{
						PrintText(L"\r\n");
					}
					else if (node->name.value == L"sp")
					{
						PrintText(L" ");
					}
					else if (node->name.value == L"tab")
					{
						PrintText(L"\t");
					}
					else if (node->name.value == L"img")
					{
						auto run = Ptr(new DocumentImageRun);
						run->baseline = -1;

						if (Ptr<XmlAttribute> source = XmlGetAttribute(node, L"source"))
						{
							run->source = source->value.value;
							WString protocol, path;
							if (IsResourceUrl(run->source, protocol, path))
							{
								Ptr<GuiImageData> imageData = resolver->ResolveResource(protocol, path).Cast<GuiImageData>();
								if (imageData)
								{
									run->image = imageData->GetImage();
								}
							}

							for (auto att : node->attributes)
							{
								if (att->name.value == L"width")
								{
									run->sizeOverride = { wtoi(att->value.value),run->sizeOverride ? run->sizeOverride.Value().y : 0 };
								}
								else if (att->name.value == L"height")
								{
									run->sizeOverride = { run->sizeOverride ? run->sizeOverride.Value().x : 0,wtoi(att->value.value) };
								}
								else if (att->name.value == L"baseline")
								{
									run->baseline = wtoi(att->value.value);
								}
								else if (att->name.value == L"frameIndex")
								{
									run->frameIndex = wtoi(att->value.value);
								}
								else if (att->name.value != L"source")
								{
									errors.Add(GuiResourceError({ {resource},att->name.codeRange.start }, L"Unknown attribute in <img>: \"" + att->name.value + L"\"."));
								}
							}

							container->runs.Add(run);
						}
						else
						{
							errors.Add(GuiResourceError({ {resource},node->codeRange.start }, L"Attribute \"source\" is missing in <img>."));
						}
					}
					else if (node->name.value == L"object")
					{
						auto run = Ptr(new DocumentEmbeddedObjectRun);
						run->baseline = -1;

						if (auto name = XmlGetAttribute(node, L"name"))
						{
							run->name = name->value.value;
							container->runs.Add(run);
						}
						else
						{
							errors.Add(GuiResourceError({ {resource},node->codeRange.start }, L"The \"name\" attribute in <object> is missing."));
						}
					}
					else if (node->name.value == L"font")
					{
						auto run = Ptr(new DocumentStylePropertiesRun);
						auto sp = Ptr(new DocumentStyleProperties);
						run->style = sp;

						for (auto att : node->attributes)
						{
							if (att->name.value == L"face")
							{
								sp->face = att->value.value;
							}
							else if (att->name.value == L"size")
							{
								sp->size = DocumentFontSize::Parse(att->value.value);
							}
							else if (att->name.value == L"color")
							{
								sp->color = Color::Parse(att->value.value);
							}
							else if (att->name.value == L"bkcolor")
							{
								sp->backgroundColor = Color::Parse(att->value.value);
							}
							else
							{
								errors.Add(GuiResourceError({ {resource},att->name.codeRange.start }, L"Unknown attribute in <font>: \"" + att->name.value + L"\"."));
							}
						}
						container->runs.Add(run);
						createdContainer = run;
					}
					else if (node->name.value == L"b" || node->name.value == L"b-")
					{
						auto run = Ptr(new DocumentStylePropertiesRun);
						run->style = Ptr(new DocumentStyleProperties);
						run->style->bold = node->name.value == L"b";
						container->runs.Add(run);
						createdContainer = run;
					}
					else if (node->name.value == L"i" || node->name.value == L"i-")
					{
						auto run = Ptr(new DocumentStylePropertiesRun);
						run->style = Ptr(new DocumentStyleProperties);
						run->style->italic = node->name.value == L"i";
						container->runs.Add(run);
						createdContainer = run;
					}
					else if (node->name.value == L"u" || node->name.value == L"u-")
					{
						auto run = Ptr(new DocumentStylePropertiesRun);
						run->style = Ptr(new DocumentStyleProperties);
						run->style->underline = node->name.value == L"u";
						container->runs.Add(run);
						createdContainer = run;
					}
					else if (node->name.value == L"s" || node->name.value == L"s-")
					{
						auto run = Ptr(new DocumentStylePropertiesRun);
						run->style = Ptr(new DocumentStyleProperties);
						run->style->strikeline = node->name.value == L"s";
						container->runs.Add(run);
						createdContainer = run;
					}
					else if (node->name.value == L"ha")
					{
						auto run = Ptr(new DocumentStylePropertiesRun);
						run->style = Ptr(new DocumentStyleProperties);
						run->style->antialias = true;
						run->style->verticalAntialias = false;
						container->runs.Add(run);
						createdContainer = run;
					}
					else if (node->name.value == L"va")
					{
						auto run = Ptr(new DocumentStylePropertiesRun);
						run->style = Ptr(new DocumentStyleProperties);
						run->style->antialias = true;
						run->style->verticalAntialias = true;
						container->runs.Add(run);
						createdContainer = run;
					}
					else if (node->name.value == L"na")
					{
						auto run = Ptr(new DocumentStylePropertiesRun);
						run->style = Ptr(new DocumentStyleProperties);
						run->style->antialias = false;
						run->style->verticalAntialias = false;
						container->runs.Add(run);
						createdContainer = run;
					}
					else if (node->name.value == L"div")
					{
						if (Ptr<XmlAttribute> att = XmlGetAttribute(node, L"style"))
						{
							WString styleName = att->value.value;

							auto run = Ptr(new DocumentStyleApplicationRun);
							run->styleName = styleName;
							container->runs.Add(run);
							createdContainer = run;
						}
						else
						{
							createdContainer = container;
						}
					}
					else if (node->name.value == L"a")
					{
						auto run = Ptr(new DocumentHyperlinkRun);
						run->normalStyleName = L"#NormalLink";
						run->activeStyleName = L"#ActiveLink";
						if (Ptr<XmlAttribute> att = XmlGetAttribute(node, L"normal"))
						{
							run->normalStyleName = att->value.value;
						}
						if (Ptr<XmlAttribute> att = XmlGetAttribute(node, L"active"))
						{
							run->activeStyleName = att->value.value;
						}
						if (Ptr<XmlAttribute> att = XmlGetAttribute(node, L"href"))
						{
							run->reference = att->value.value;
						}
						run->styleName = run->normalStyleName;
						container->runs.Add(run);
						createdContainer = run;
					}
					else if (node->name.value == L"p")
					{
						for (auto sub : node->subNodes)
						{
							sub->Accept(this);
						}
					}
					else
					{
						if (node->name.value != L"nop")
						{
							errors.Add(GuiResourceError({ {resource},node->codeRange.start }, L"Unknown element in <p>: \"" + node->name.value + L"\"."));
						}
						for (auto sub : node->subNodes)
						{
							sub->Accept(this);
						}
					}

					if (createdContainer)
					{
						Ptr<DocumentContainerRun> oldContainer = container;
						container = createdContainer;
						for (auto subNode : subNodeContainer->subNodes)
						{
							subNode->Accept(this);
						}
						container = oldContainer;
					}
				}

				void Visit(XmlInstruction* node)override
				{
				}

				void Visit(XmlDocument* node)override
				{
				}
			};

			Ptr<DocumentStyle> ParseDocumentStyle(Ptr<GuiResourceItem> resource, Ptr<XmlElement> styleElement, GuiResourceError::List& errors)
			{
				auto style = Ptr(new DocumentStyle);

				if(Ptr<XmlAttribute> parent=XmlGetAttribute(styleElement, L"parent"))
				{
					style->parentStyleName=parent->value.value;
				}

				auto sp = Ptr(new DocumentStyleProperties);
				style->styles=sp;

				for (auto att : XmlGetElements(styleElement))
				{
					if(att->name.value==L"face")
					{
						sp->face=XmlGetValue(att);
					}
					else if(att->name.value==L"size")
					{
						sp->size=DocumentFontSize::Parse(XmlGetValue(att));
					}
					else if(att->name.value==L"color")
					{
						sp->color=Color::Parse(XmlGetValue(att));
					}
					else if(att->name.value==L"bkcolor")
					{
						sp->backgroundColor=Color::Parse(XmlGetValue(att));
					}
					else if(att->name.value==L"b")
					{
						sp->bold=XmlGetValue(att)==L"true";
					}
					else if(att->name.value==L"i")
					{
						sp->italic=XmlGetValue(att)==L"true";
					}
					else if(att->name.value==L"u")
					{
						sp->underline=XmlGetValue(att)==L"true";
					}
					else if(att->name.value==L"s")
					{
						sp->strikeline=XmlGetValue(att)==L"true";
					}
					else if(att->name.value==L"antialias")
					{
						WString value=XmlGetValue(att);
						if(value==L"horizontal" || value==L"default")
						{
							sp->antialias=true;
							sp->verticalAntialias=false;
						}
						else if(value==L"no")
						{
							sp->antialias=false;
							sp->verticalAntialias=false;
						}
						else if(value==L"vertical")
						{
							sp->antialias=true;
							sp->verticalAntialias=true;
						}
					}
					else
					{
						errors.Add(GuiResourceError({ {resource},att->codeRange.start }, L"Unknown element in <Style>: \"" + att->name.value + L"\"."));
					}
				}

				return style;
			}
		}
		using namespace document_operation_visitors;

/***********************************************************************
DocumentModel
***********************************************************************/

		Ptr<DocumentModel> DocumentModel::LoadFromXml(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlDocument> xml, Ptr<GuiResourcePathResolver> resolver, GuiResourceError::List& errors)
		{
			auto model = Ptr(new DocumentModel);
			if (xml->rootElement->name.value == L"Doc")
			{
				for (auto partElement : XmlGetElements(xml->rootElement))
				{
					if (partElement->name.value == L"Styles")
					{
						for (auto styleElement : XmlGetElements(partElement))
						{
							if (styleElement->name.value == L"Style")
							{
								if (Ptr<XmlAttribute> name = XmlGetAttribute(styleElement, L"name"))
								{
									auto style = ParseDocumentStyle(resource, styleElement, errors);
									auto styleName = name->value.value;
									if (!model->styles.Keys().Contains(styleName))
									{
										model->styles.Add(styleName, style);
										if (styleName.Length() > 9 && styleName.Right(9) == L"-Override")
										{
											auto overridedStyle = Ptr(new DocumentStyle);
											overridedStyle->styles = Ptr(new DocumentStyleProperties);
											MergeStyle(overridedStyle->styles, style->styles);

											styleName = styleName.Left(styleName.Length() - 9);
											auto index = model->styles.Keys().IndexOf(styleName);
											if (index == -1)
											{
												model->styles.Add(styleName, overridedStyle);
											}
											else
											{
												auto originalStyle = model->styles.Values()[index];
												MergeStyle(overridedStyle->styles, originalStyle->styles);
												originalStyle->styles = overridedStyle->styles;
											}
										}
									}
								}
								else
								{
									errors.Add(GuiResourceError({ {resource},styleElement->codeRange.start }, L"Attribute \"name\" is missing in <Style>."));
								}
							}
							else
							{
								errors.Add(GuiResourceError({ {resource},styleElement->codeRange.start }, L"Unknown element in <Styles>: \"" + styleElement->name.value + L"\"."));
							}
						}
					}
					else if (partElement->name.value == L"Content")
					{
						for (auto [p, i] : indexed(XmlGetElements(partElement)))
						{
							if (p->name.value == L"p")
							{
								auto paragraph = Ptr(new DocumentParagraphRun);
								if (Ptr<XmlAttribute> att = XmlGetAttribute(p, L"align"))
								{
									if (att->value.value == L"Left")
									{
										paragraph->alignment = Alignment::Left;
									}
									else if (att->value.value == L"Center")
									{
										paragraph->alignment = Alignment::Center;
									}
									else if (att->value.value == L"Right")
									{
										paragraph->alignment = Alignment::Right;
									}
									else
									{
										errors.Add(GuiResourceError({ {resource},att->value.codeRange.start }, L"Unknown value in align attribute \"" + att->value.value + L"\"."));
									}
								}
								model->paragraphs.Add(paragraph);
								DeserializeNodeVisitor visitor(model, paragraph, i, resource, resolver, errors);
								p->Accept(&visitor);
							}
							else
							{
								errors.Add(GuiResourceError({ {resource},p->codeRange.start }, L"Unknown element in <Content>: \"" + p->name.value + L"\"."));
							}
						}
					}
					else
					{
						errors.Add(GuiResourceError({ {resource},partElement->codeRange.start }, L"Unknown element in <Doc>: \"" + partElement->name.value + L"\"."));
					}
				}
			}
			else
			{
				errors.Add(GuiResourceError({ {resource},xml->rootElement->codeRange.start }, L"The root element of document should be \"Doc\"."));
			}
			return model;
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIDOCUMENT_SAVE.CPP
***********************************************************************/

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

/***********************************************************************
document_operation_visitors::SerializeRunVisitor
***********************************************************************/

		namespace document_operation_visitors
		{
			class SerializeRunVisitor : public Object, public DocumentRun::IVisitor
			{
			protected:
				Ptr<XmlElement>				parent;

			public:
				SerializeRunVisitor(Ptr<XmlElement> _parent)
					:parent(_parent)
				{
				}

				void VisitContainer(Ptr<XmlElement> replacedParent, DocumentContainerRun* run)
				{
					if (replacedParent)
					{
						parent->subNodes.Add(replacedParent);
						Ptr<XmlElement> oldParent = parent;
						parent = replacedParent;
						for (auto subRun : run->runs)
						{
							subRun->Accept(this);
						}
						parent = oldParent;
					}
					else
					{
						for (auto subRun : run->runs)
						{
							subRun->Accept(this);
						}
					}
				}

				void Visit(DocumentTextRun* run)override
				{
					auto begin = run->text.Buffer();
					auto end = begin + run->text.Length();
					while (*begin == L'\r') begin++;
					while (end > begin && end[-1] == L'\r') end--;
					if (begin == end) return;

					auto beginWithTag = *begin == L'\n' || *begin == L' ' || *begin == L'\t';
					auto endWithTag = end > begin && (end[-1] == L'\n' || end[-1] == L' ' || end[-1] == L'\t');
					auto wrappedByNop = !beginWithTag || !endWithTag;
					auto writer = wrappedByNop ? XmlElementWriter(parent).Element(L"nop") : XmlElementWriter(parent);

					auto reading = begin;
					auto last = reading;
					while (true)
					{
						auto c = *reading;
						const wchar_t* tag = nullptr;

						switch (c)
						{
						case L'\n':
							tag = L"br";
							break;
						case L' ':
							if (!wrappedByNop && (reading == begin || reading == end - 1))
							{
								tag = L"sp";
							}
							break;
						case L'\t':
							if (!wrappedByNop && (reading == begin || reading == end - 1))
							{
								tag = L"tab";
							}
							break;
						}

						if (tag || reading == end)
						{
							if (reading > last)
							{
								auto end = reading[-1] == L'\r' ? reading - 1 : reading;
								if (end > last)
								{
									writer.Text(run->text.Sub(last - begin, end - last));
								}
								last = reading;
							}
						}

						if (tag)
						{
							writer.Element(tag);
							last++;
						}
						else if (reading == end)
						{
							break;
						}
						reading++;
					}
				}

				void Visit(DocumentStylePropertiesRun* run)override
				{
					Ptr<DocumentStyleProperties> sp = run->style;
					Ptr<XmlElement> oldParent = parent;
					if (sp->face || sp->size || sp->color)
					{
						auto element = Ptr(new XmlElement);
						element->name.value = L"font";
						parent->subNodes.Add(element);

						XmlElementWriter writer(element);
						if (sp->face)
						{
							writer.Attribute(L"face", sp->face.Value());
						}
						if (sp->size)
						{
							writer.Attribute(L"size", sp->size.Value().ToString());
						}
						if (sp->color)
						{
							writer.Attribute(L"color", sp->color.Value().ToString());
						}
						if (sp->backgroundColor)
						{
							writer.Attribute(L"bkcolor", sp->backgroundColor.Value().ToString());
						}
						parent = element;
					}
					if (sp->bold)
					{
						auto element = Ptr(new XmlElement);
						element->name.value = sp->bold.Value() ? L"b" : L"b-";
						parent->subNodes.Add(element);
						parent = element;
					}
					if (sp->italic)
					{
						auto element = Ptr(new XmlElement);
						element->name.value = sp->italic.Value() ? L"i" : L"i-";
						parent->subNodes.Add(element);
						parent = element;
					}
					if (sp->underline)
					{
						auto element = Ptr(new XmlElement);
						element->name.value = sp->underline.Value() ? L"u" : L"u-";
						parent->subNodes.Add(element);
						parent = element;
					}
					if (sp->strikeline)
					{
						auto element = Ptr(new XmlElement);
						element->name.value = sp->strikeline.Value() ? L"s" : L"s-";
						parent->subNodes.Add(element);
						parent = element;
					}
					if (sp->antialias || sp->verticalAntialias)
					{
						bool ha = sp->antialias ? sp->antialias.Value() : true;
						bool va = sp->verticalAntialias ? sp->verticalAntialias.Value() : false;
						if (!ha)
						{
							auto element = Ptr(new XmlElement);
							element->name.value = L"ha";
							parent->subNodes.Add(element);
							parent = element;
						}
						else if (!va)
						{
							auto element = Ptr(new XmlElement);
							element->name.value = L"va";
							parent->subNodes.Add(element);
							parent = element;
						}
						else
						{
							auto element = Ptr(new XmlElement);
							element->name.value = L"na";
							parent->subNodes.Add(element);
							parent = element;
						}
					}
					VisitContainer(0, run);
					parent = oldParent;
				}

				void Visit(DocumentStyleApplicationRun* run)override
				{
					auto element = Ptr(new XmlElement);
					element->name.value = L"div";
					XmlElementWriter(element).Attribute(L"style", run->styleName);
					VisitContainer(element, run);
				}

				void Visit(DocumentHyperlinkRun* run)override
				{
					auto element = Ptr(new XmlElement);
					element->name.value = L"a";
					XmlElementWriter writer(element);
					if (run->normalStyleName != L"#NormalLink")
					{
						writer.Attribute(L"normal", run->normalStyleName);
					}
					if (run->activeStyleName != L"#ActiveLink")
					{
						writer.Attribute(L"active", run->activeStyleName);
					}
					if (run->reference != L"")
					{
						writer.Attribute(L"href", run->reference);
					}
					VisitContainer(element, run);
				}

				void Visit(DocumentImageRun* run)override
				{
					XmlElementWriter writer(parent);
					auto elementWriter = writer
						.Element(L"img")
						.Attribute(L"frameIndex", itow(run->frameIndex))
						.Attribute(L"source", run->source)
						;
					if(run->sizeOverride)
					{
						elementWriter
							.Attribute(L"width", itow(run->sizeOverride.Value().x))
							.Attribute(L"height", itow(run->sizeOverride.Value().y))
							;
					}
					if (run->baseline != -1)
					{
						elementWriter.Attribute(L"baseline", itow(run->baseline));
					}
				}

				void Visit(DocumentEmbeddedObjectRun* run)override
				{
					XmlElementWriter writer(parent);
					writer
						.Element(L"object")
						.Attribute(L"name", run->name)
						;
				}

				void Visit(DocumentParagraphRun* run)override
				{
					auto element = Ptr(new XmlElement);
					element->name.value = L"p";

					XmlElementWriter writer(element);
					if (run->alignment)
					{
						switch (run->alignment.Value())
						{
						case Alignment::Left:
							writer.Attribute(L"align", L"Left");
							break;
						case Alignment::Center:
							writer.Attribute(L"align", L"Center");
							break;
						case Alignment::Right:
							writer.Attribute(L"align", L"Right");
							break;
						}
					}
					VisitContainer(element, run);
				}
			};
		}
		using namespace document_operation_visitors;

/***********************************************************************
DocumentModel
***********************************************************************/

		Ptr<glr::xml::XmlDocument> DocumentModel::SaveToXml()
		{
			auto xml = Ptr(new XmlDocument);
			auto doc = Ptr(new XmlElement);
			doc->name.value=L"Doc";
			xml->rootElement=doc;
			{
				auto content = Ptr(new XmlElement);
				content->name.value=L"Content";
				doc->subNodes.Add(content);
				
				for (auto p : paragraphs)
				{
					SerializeRunVisitor visitor(content);
					p->Accept(&visitor);
				}
			}
			{
				auto stylesElement = Ptr(new XmlElement);
				stylesElement->name.value=L"Styles";
				doc->subNodes.Add(stylesElement);

				// TODO: (enumerable) foreach
				for(vint i=0;i<styles.Count();i++)
				{
					WString name=styles.Keys()[i];
					if (name.Length()>0 && name[0] == L'#' && (name.Length() <= 9 || name.Right(9) != L"-Override")) continue;

					Ptr<DocumentStyle> style=styles.Values().Get(i);
					Ptr<DocumentStyleProperties> sp=style->styles;
					auto styleElement = Ptr(new XmlElement);
					styleElement->name.value=L"Style";
					stylesElement->subNodes.Add(styleElement);

					XmlElementWriter(styleElement).Attribute(L"name", name);
					if(style->parentStyleName!=L"")
					{
						XmlElementWriter(styleElement).Attribute(L"parent", style->parentStyleName);
					}

					if(sp->face)				XmlElementWriter(styleElement).Element(L"face").Text(		sp->face.Value()						);
					if(sp->size)				XmlElementWriter(styleElement).Element(L"size").Text(		sp->size.Value().ToString()				);
					if(sp->color)				XmlElementWriter(styleElement).Element(L"color").Text(		sp->color.Value().ToString()			);
					if(sp->backgroundColor)		XmlElementWriter(styleElement).Element(L"bkcolor").Text(	sp->backgroundColor.Value().ToString()	);
					if(sp->bold)				XmlElementWriter(styleElement).Element(L"b").Text(			sp->bold.Value()?L"true":L"false"		);
					if(sp->italic)				XmlElementWriter(styleElement).Element(L"i").Text(			sp->italic.Value()?L"true":L"false"		);
					if(sp->underline)			XmlElementWriter(styleElement).Element(L"u").Text(			sp->underline.Value()?L"true":L"false"	);
					if(sp->strikeline)			XmlElementWriter(styleElement).Element(L"s").Text(			sp->strikeline.Value()?L"true":L"false"	);
					if(sp->antialias && sp->verticalAntialias)
					{
						bool h=sp->antialias;
						bool v=sp->verticalAntialias;
						if(!h)
						{
							XmlElementWriter(styleElement).Element(L"antialias").Text(L"no");
						}
						else if(!v)
						{
							XmlElementWriter(styleElement).Element(L"antialias").Text(L"horizontal");
						}
						else
						{
							XmlElementWriter(styleElement).Element(L"antialias").Text(L"vertical");
						}
					}
				}
			}
			return xml;
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIPARSERMANAGER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace glr::xml;
		using namespace glr::json;
		using namespace regex;

/***********************************************************************
IGuiParserManager
***********************************************************************/

		IGuiParserManager* parserManager=0;

		IGuiParserManager* GetParserManager()
		{
			return parserManager;
		}

		class GuiParser_Xml : public IGuiParser<XmlDocument>
		{
		protected:
			glr::xml::Parser							parser;

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

		class GuiParser_Json : public IGuiParser<JsonNode>
		{
		protected:
			glr::json::Parser							parser;

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

		class GuiParserManager : public Object, public IGuiParserManager, public IGuiPlugin
		{
		protected:
			SpinLock									lock;

			Dictionary<WString, Ptr<IGuiGeneralParser>>	parsers;
		public:
			
			GUI_PLUGIN_NAME(GacUI_Parser)
			{
			}

			void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerUnrelatedPlugins)
				{
					parserManager = this;
					SetParser(L"XML", Ptr(new GuiParser_Xml()));
					SetParser(L"JSON", Ptr(new GuiParser_Json()));
				}
			}

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

			Ptr<IGuiGeneralParser> GetParser(const WString& name)override
			{
				vint index=parsers.Keys().IndexOf(name);
				return index == -1 ? nullptr : parsers.Values()[index];
			}

			bool SetParser(const WString& name, Ptr<IGuiGeneralParser> parser)override
			{
				if(parsers.Keys().Contains(name)) return false;
				parsers.Add(name, parser);
				return true;
			}
		};
		GUI_REGISTER_PLUGIN(GuiParserManager)
	}
}

/***********************************************************************
.\RESOURCES\GUIPLUGINMANAGER.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;

/***********************************************************************
GuiPluginManager
***********************************************************************/

		class GuiPluginManager : public Object, public IGuiPluginManager
		{
		protected:
			List<Ptr<IGuiPlugin>>				plugins;
			bool								controllerRelatedLoaded = false;
			bool								controllerUnrelatedLoaded = false;
		public:
			GuiPluginManager()
			{
			}

			~GuiPluginManager()
			{
			}

			void AddPlugin(Ptr<IGuiPlugin> plugin)override
			{
#define ERROR_MESSAGE_PREFIX L"GuiPluginManager::AddPlugin(Ptr<IGuiPlugin>)#"
				CHECK_ERROR(!controllerUnrelatedLoaded, ERROR_MESSAGE_PREFIX L"Load function has already been executed.");
				auto name = plugin->GetName();
				if (name != L"")
				{
					for (auto plugin : plugins)
					{
						CHECK_ERROR(plugin->GetName() != name, ERROR_MESSAGE_PREFIX L"Duplicated plugin name.");
					}
				}
				plugins.Add(plugin);
#undef ERROR_MESSAGE_PREFIX
			}

			void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
#define ERROR_MESSAGE_PREFIX L"GuiPluginManager::Load(bool, bool)#"
				CHECK_ERROR(controllerUnrelatedPlugins || controllerRelatedPlugins, L"At least one of the parameters should be true.");
				if (controllerUnrelatedPlugins)
				{
					CHECK_ERROR(!controllerUnrelatedLoaded, ERROR_MESSAGE_PREFIX L"A second Load(true, *) could only be called after Unload(true, *).");
					controllerUnrelatedLoaded = true;
				}
				if (controllerRelatedPlugins)
				{
					CHECK_ERROR(controllerUnrelatedLoaded, ERROR_MESSAGE_PREFIX L"Load(*, true) could only be called between Load(true, *) and Unload(true, *).");
					CHECK_ERROR(!controllerRelatedLoaded, ERROR_MESSAGE_PREFIX L"A second Load(*, true) could only be called after Unload(*, true).");
					controllerRelatedLoaded = true;
				}

				SortedList<WString> loaded;
				Group<WString, WString> loading;
				Dictionary<WString, Ptr<IGuiPlugin>> pluginsToLoad;
				for (auto plugin : plugins)
				{
					auto name = plugin->GetName();
					pluginsToLoad.Add(name, plugin);
					List<WString> dependencies;
					plugin->GetDependencies(dependencies);
					for (auto dependency : dependencies)
					{
						loading.Add(name, dependency);
					}
				}

				while (pluginsToLoad.Count() > 0)
				{
					vint count = pluginsToLoad.Count();
					{
						// TODO: (enumerable) foreach:alterable(reversed) on dictionary
						for (auto [name, index] : indexed(pluginsToLoad.Keys()))
						{
							if (!loading.Keys().Contains(name))
							{
								// TODO: (enumerable) foreach:alterable(reversed) on group
								for (vint i = loading.Count() - 1; i >= 0; i--)
								{
									loading.Remove(loading.Keys()[i], name);
								}
								loaded.Add(name);

								auto plugin = pluginsToLoad.Values()[index];
								pluginsToLoad.Remove(name);
								plugin->Load(controllerUnrelatedPlugins, controllerRelatedPlugins);
								break;
							}
						}
					}
					if (count == pluginsToLoad.Count())
					{
						WString message;
						for (auto plugin : pluginsToLoad.Values())
						{
							message += L"Cannot load plugin \"" + plugin->GetName() + L"\" because part of its dependencies are not ready:";
							List<WString> dependencies;
							plugin->GetDependencies(dependencies);
							bool first = true;
							for (auto dependency : dependencies)
							{
								if (!loaded.Contains(dependency))
								{
									message += L" \"" + dependency + L"\";";
								}
							}
							message += L"\r\n";
						}
						throw Exception(message);
					}
				}
#undef ERROR_MESSAGE_PREFIX
			}

			void Unload(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
#define ERROR_MESSAGE_PREFIX L"GuiPluginManager::Unload(bool, bool)#"
				CHECK_ERROR(controllerUnrelatedPlugins || controllerRelatedPlugins, L"At least one of the parameters should be true.");
				if (controllerRelatedPlugins)
				{
					CHECK_ERROR(controllerUnrelatedLoaded, ERROR_MESSAGE_PREFIX L"Unload(*, true) could only be called between Load(true, *) and Unload(true, *).");
					CHECK_ERROR(controllerRelatedLoaded, ERROR_MESSAGE_PREFIX L"Unload(*, true) could only be called after Load(*, true).");
					controllerRelatedLoaded = false;
				}
				if (controllerUnrelatedPlugins)
				{
					CHECK_ERROR(controllerUnrelatedLoaded, ERROR_MESSAGE_PREFIX L"Unload(true, *) could only be called after Load(true, *).");
					CHECK_ERROR(!controllerRelatedLoaded, ERROR_MESSAGE_PREFIX L"Unload(true, *) could only be called after Load(*, true).");
					controllerUnrelatedLoaded = false;
				}

				for (auto plugin : plugins)
				{
					plugin->Unload(controllerUnrelatedPlugins, controllerRelatedPlugins);
				}
#undef ERROR_MESSAGE_PREFIX
			}

			bool IsControllerRelatedPluginsLoaded()override
			{
				return controllerRelatedLoaded;
			}

			bool IsControllerUnrelatedPluginsLoaded()override
			{
				return controllerUnrelatedLoaded;
			}
		};

/***********************************************************************
Helpers
***********************************************************************/

		GuiPluginDescriptor* firstPluginDescriptor = nullptr;
		GuiPluginDescriptor** lastPluginDescriptor = &firstPluginDescriptor;
		IGuiPluginManager* pluginManager = nullptr;

		IGuiPluginManager* GetPluginManager()
		{
			if (!pluginManager)
			{
				pluginManager = new GuiPluginManager;

				auto current = firstPluginDescriptor;
				while (current)
				{
					pluginManager->AddPlugin(current->CreatePlugin());
					current = current->next;
				}
			}
			return pluginManager;
		}

		void RegisterPluginDescriptor(GuiPluginDescriptor* pluginDescriptor)
		{
			CHECK_ERROR(!pluginManager, L"vl::presentation::RegisterPluginDescriptor(GuiPluginDescriptor*)#This function should be called before calling GetPluginManager.");
			*lastPluginDescriptor = pluginDescriptor;
			lastPluginDescriptor = &pluginDescriptor->next;
		}

		void DestroyPluginManager()
		{
			if (pluginManager)
			{
				CHECK_ERROR(
					!pluginManager->IsControllerRelatedPluginsLoaded() && !pluginManager->IsControllerUnrelatedPluginsLoaded(),
					L"vl::presentation::DestroyPluginManager()#Plugins have not been unloaded.");
				delete pluginManager;
				pluginManager = nullptr;
			}
		}
	}
}

/***********************************************************************
.\RESOURCES\GUIRESOURCE.CPP
***********************************************************************/

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

		WString GetFolderPath(const WString& filePath)
		{
			auto path = FilePath(filePath).GetFolder().GetFullPath();
			if (path != L"")
			{
				if (path[path.Length() - 1] != FilePath::GetPathDelimiter())
				{
					path += WString::FromChar(FilePath::GetPathDelimiter());
				}
			}
			return path;
		}

		WString GetFileName(const WString& filePath)
		{
			return FilePath(filePath).GetName();
		}

		bool LoadTextFile(const WString& filePath, WString& text)
		{
			BomEncoder::Encoding encoding;
			bool bom;
			return File(filePath).ReadAllTextWithEncodingTesting(text, encoding, bom);
		}

		bool IsResourceUrl(const WString& text, WString& protocol, WString& path)
		{
			Pair<vint, vint> index = INVLOC.FindFirst(text, L"://", Locale::None);
			if (index.key != -1)
			{
				protocol = INVLOC.ToLower(text.Sub(0, index.key));
				path = text.Sub(index.key + index.value, text.Length() - index.key - index.value);
				return true;
			}
			else
			{
				return false;
			}
		}

		vint HexToInt(wchar_t c)
		{
			if (L'0' <= c && c <= L'9')
			{
				return c - L'0';
			}
			else if (L'A' <= c && c <= L'F')
			{
				return c - L'A' + 10;
			}
			else
			{
				return 0;
			}
		}

		void HexToBinary(stream::IStream& binaryStream, const WString& hexText)
		{
			const wchar_t* buffer = hexText.Buffer();
			vint count = hexText.Length() / 2;
			for (vint i = 0; i < count; i++)
			{
				vuint8_t byte = (vuint8_t)(HexToInt(buffer[0]) * 16 + HexToInt(buffer[1]));
				buffer += 2;
				binaryStream.Write(&byte, 1);
			}
		}

		WString BinaryToHex(stream::IStream& binaryStream)
		{
			stream::MemoryStream memoryStream;
			{
				stream::StreamWriter writer(memoryStream);
				vuint8_t byte;
				while (binaryStream.Read(&byte, 1) == 1)
				{
					writer.WriteChar(L"0123456789ABCDEF"[byte / 16]);
					writer.WriteChar(L"0123456789ABCDEF"[byte % 16]);
				}
			}
			memoryStream.SeekFromBegin(0);
			{
				stream::StreamReader reader(memoryStream);
				return reader.ReadToEnd();
			}
		}

/***********************************************************************
GlobalStringKey
***********************************************************************/

		GlobalStringKey GlobalStringKey::Empty;
		GlobalStringKey GlobalStringKey::_InferType;
		GlobalStringKey GlobalStringKey::_Set;
		GlobalStringKey GlobalStringKey::_Ref;
		GlobalStringKey GlobalStringKey::_Bind;
		GlobalStringKey GlobalStringKey::_Format;
		GlobalStringKey GlobalStringKey::_Str;
		GlobalStringKey GlobalStringKey::_Eval;
		GlobalStringKey GlobalStringKey::_Uri;
		GlobalStringKey GlobalStringKey::_ControlTemplate;

		class GlobalStringKeyManager
		{
		public:
			Dictionary<WString, vint>		stoi;
			List<WString>					itos;

			void InitializeConstants()
			{
				GlobalStringKey::_Set = GlobalStringKey::Get(L"set");
				GlobalStringKey::_InferType = GlobalStringKey::Get(L"_");
				GlobalStringKey::_Ref = GlobalStringKey::Get(L"ref");
				GlobalStringKey::_Bind = GlobalStringKey::Get(L"bind");
				GlobalStringKey::_Format = GlobalStringKey::Get(L"format");
				GlobalStringKey::_Str = GlobalStringKey::Get(L"str");
				GlobalStringKey::_Eval = GlobalStringKey::Get(L"eval");
				GlobalStringKey::_Uri = GlobalStringKey::Get(L"uri");
				GlobalStringKey::_ControlTemplate = GlobalStringKey::Get(L"ControlTemplate");
			}
		}*globalStringKeyManager = 0;

		GlobalStringKey GlobalStringKey::Get(const WString& string)
		{
			GlobalStringKey key;
			if (string != L"")
			{
				vint index = globalStringKeyManager->stoi.Keys().IndexOf(string);
				if (index == -1)
				{
					key.key = globalStringKeyManager->itos.Add(string);
					globalStringKeyManager->stoi.Add(string, key.key);
				}
				else
				{
					key.key = globalStringKeyManager->stoi.Values()[index];
				}
			}
			return key;
		}

		vint GlobalStringKey::ToKey()const
		{
			return key;
		}

		WString GlobalStringKey::ToString()const
		{
			return *this == GlobalStringKey::Empty
				? L""
				: globalStringKeyManager->itos[key];
		}

/***********************************************************************
GuiImageData
***********************************************************************/

		GuiImageData::GuiImageData()
			:frameIndex(-1)
		{
		}

		GuiImageData::GuiImageData(Ptr<INativeImage> _image, vint _frameIndex)
			: image(_image)
			, frameIndex(_frameIndex)
		{
		}

		GuiImageData::~GuiImageData()
		{
		}

		Ptr<INativeImage> GuiImageData::GetImage()
		{
			return image;
		}

		vint GuiImageData::GetFrameIndex()
		{
			return frameIndex;
		}

/***********************************************************************
GuiTextData
***********************************************************************/

		GuiTextData::GuiTextData()
		{
		}

		GuiTextData::GuiTextData(const WString& _text)
			:text(_text)
		{
		}

		WString GuiTextData::GetText()
		{
			return text;
		}

/***********************************************************************
GuiResourceNodeBase
***********************************************************************/

		GuiResourceNodeBase::GuiResourceNodeBase()
			:parent(0)
		{
		}

		GuiResourceNodeBase::~GuiResourceNodeBase()
		{
		}

		const WString& GuiResourceNodeBase::GetName()
		{
			return name;
		}

		WString GuiResourceNodeBase::GetResourcePath()
		{
			auto resourcePath = name;
			auto current = parent;
			while (current && current->GetParent())
			{
				resourcePath = current->GetName() + L"/" + resourcePath;
				current = current->GetParent();
			}
			return resourcePath;
		}

		const WString& GuiResourceNodeBase::GetFileContentPath()
		{
			return fileContentPath;
		}

		const WString& GuiResourceNodeBase::GetFileAbsolutePath()
		{
			return fileAbsolutePath;
		}

		void GuiResourceNodeBase::SetFileContentPath(const WString& content, const WString& absolute)
		{
			fileContentPath = content;
			fileAbsolutePath = absolute;
		}

		GuiResourceFolder* GuiResourceNodeBase::GetParent()
		{
			return parent;
		}

/***********************************************************************
GuiResourceLocation
***********************************************************************/

		GuiResourceLocation::GuiResourceLocation(const WString& _resourcePath, const WString& _filePath)
			:resourcePath(_resourcePath)
			, filePath(_filePath)
		{
		}

		GuiResourceLocation::GuiResourceLocation(Ptr<GuiResourceNodeBase> node)
		{
			if (node)
			{
				resourcePath = node->GetResourcePath();

				auto current = node.Obj();
				while (current)
				{
					if (current->GetFileContentPath() != L"")
					{
						filePath = current->GetFileAbsolutePath();
						break;
					}
					current = current->GetParent();
				}
			}
		}

/***********************************************************************
GuiResourceTextPos
***********************************************************************/

		GuiResourceTextPos::GuiResourceTextPos(GuiResourceLocation location, glr::ParsingTextPos position)
			:originalLocation(location)
			, row(position.row)
			, column(position.column)
		{
		}

/***********************************************************************
GuiResourceError
***********************************************************************/

		GuiResourceError::GuiResourceError(GuiResourceTextPos _position, const WString& _message)
			:location(_position.originalLocation)
			, position(_position)
			, message(_message)
		{
		}

		GuiResourceError::GuiResourceError(GuiResourceLocation _location, const WString& _message)
			:location(_location)
			, position(_location, {})
			, message(_message)
		{
		}

		GuiResourceError::GuiResourceError(GuiResourceLocation _location, GuiResourceTextPos _position, const WString& _message)
			:location(_location)
			, position(_position)
			, message(_message)
		{
		}

		template<typename TCallback>
		void TransformErrors(GuiResourceError::List& errors, collections::List<glr::ParsingError>& parsingErrors, GuiResourceTextPos offset, const TCallback& callback)
		{
			if (offset.row < 0 || offset.column < 0)
			{
				offset.row = 0;
				offset.column = 0;
			}

			for (auto error : parsingErrors)
			{
				auto pos = error.codeRange.start;
				if (pos.row < 0 || pos.column < 0)
				{
					pos = { offset.row,offset.column };
				}
				else
				{
					if (pos.row == 0)
					{
						pos.column += offset.column;
					}
					pos.row += offset.row;
				}
				errors.Add(callback({ offset.originalLocation,pos }, error.message));
			}
		}

		void GuiResourceError::Transform(GuiResourceLocation _location, GuiResourceError::List& errors, collections::List<glr::ParsingError>& parsingErrors)
		{
			Transform(_location, errors, parsingErrors, { _location,{ 0,0 } });
		}

		void GuiResourceError::Transform(GuiResourceLocation _location, GuiResourceError::List& errors, collections::List<glr::ParsingError>& parsingErrors, glr::ParsingTextPos offset)
		{
			Transform(_location, errors, parsingErrors, { _location,offset });
		}

		void GuiResourceError::Transform(GuiResourceLocation _location, GuiResourceError::List& errors, collections::List<glr::ParsingError>& parsingErrors, GuiResourceTextPos offset)
		{
			TransformErrors(errors, parsingErrors, offset, [&](GuiResourceTextPos pos, const WString& message)
			{
				return GuiResourceError(_location, pos, message);
			});
		}

		void GuiResourceError::SortAndLog(List& errors, collections::List<WString>& output, const WString& workingDirectory)
		{
			if (errors.Count() == 0) return;
			Sort(&errors[0], errors.Count());

			for (vint index = 0; index < errors.Count(); index++)
			{
				auto& error = errors[index];
				bool needHeader = index == 0;
				if (index > 0)
				{
					auto previousError = errors[index - 1];
					if (error.location != previousError.location || error.position.originalLocation != previousError.position.originalLocation)
					{
						needHeader = true;
					}
				}

#define CONVERT_FILEPATH(FILEPATH) (workingDirectory == L"" ? FILEPATH  : filesystem::FilePath(workingDirectory).GetRelativePathFor(FILEPATH))
#define CONVERT_LOCATION(LOCATION) (LOCATION).resourcePath + L" # " + CONVERT_FILEPATH((LOCATION).filePath)
				if (needHeader)
				{
					output.Add(CONVERT_LOCATION(error.location));
					if (error.location != error.position.originalLocation)
					{
						output.Add(L"    Original: " + CONVERT_LOCATION(error.position.originalLocation));
					}
				}

				WString prefix = L"Failed to load file \"";
				WString postfix = L"\".";
				if (INVLOC.StartsWith(error.message, prefix, Locale::Normalization::None) && INVLOC.EndsWith(error.message, postfix, Locale::Normalization::None))
				{
					auto path = error.message.Sub(prefix.Length(), error.message.Length() - prefix.Length() - postfix.Length());
					path = CONVERT_FILEPATH(path);
					error.message = prefix + path + postfix;
				}

				auto row = error.position.row;
				if (row >= 0) row++;
				auto column = error.position.column;
				if (column >= 0) column++;
				output.Add(L"(" + itow(row) + L", " + itow(column) + L"): " + error.message);
#undef CONVERT_FILEPATH
#undef CONVERT_LOCATION
			}
		}

/***********************************************************************
GuiResourceItem
***********************************************************************/

		GuiResourceItem::GuiResourceItem()
		{
		}

		GuiResourceItem::~GuiResourceItem()
		{
		}

		const WString& GuiResourceItem::GetTypeName()
		{
			return typeName;
		}

		Ptr<DescriptableObject> GuiResourceItem::GetContent()
		{
			return content;
		}

		void GuiResourceItem::SetContent(const WString& _typeName, Ptr<DescriptableObject> value)
		{
			typeName = _typeName;
			content = value;
		}

		Ptr<GuiImageData> GuiResourceItem::AsImage()
		{
			return content.Cast<GuiImageData>();
		}

		Ptr<glr::xml::XmlDocument> GuiResourceItem::AsXml()
		{
			return content.Cast<XmlDocument>();
		}

		Ptr<GuiTextData> GuiResourceItem::AsString()
		{
			return content.Cast<GuiTextData>();
		}

		Ptr<DocumentModel> GuiResourceItem::AsDocument()
		{
			return content.Cast<DocumentModel>();
		}

/***********************************************************************
GuiResourceFolder
***********************************************************************/

		void GuiResourceFolder::LoadResourceFolderFromXml(DelayLoadingList& delayLoadings, const WString& containingFolder, Ptr<glr::xml::XmlElement> folderXml, GuiResourceError::List& errors)
		{
			ClearItems();
			ClearFolders();
			for (auto element : XmlGetElements(folderXml))
			{
				WString name;
				if (Ptr<XmlAttribute> nameAtt = XmlGetAttribute(element, L"name"))
				{
					name = nameAtt->value.value;
				}
				if (element->name.value == L"Folder")
				{
					if (name == L"")
					{
						errors.Add(GuiResourceError({ {Ptr(this)},element->codeRange.start }, L"A resource folder should have a name."));
					}
					else
					{
						auto folder = Ptr(new GuiResourceFolder);
						if (AddFolder(name, folder))
						{
							WString newContainingFolder = containingFolder;
							Ptr<XmlElement> newFolderXml = element;
							if (Ptr<XmlAttribute> contentAtt = XmlGetAttribute(element, L"content"))
							{
								if (contentAtt->value.value == L"Link")
								{
									auto fileContentPath = XmlGetValue(element);
									auto fileAbsolutePath = containingFolder + fileContentPath;
									folder->SetFileContentPath(fileContentPath, fileAbsolutePath);

									WString text;
									if (LoadTextFile(fileAbsolutePath, text))
									{
										if (auto parser = GetParserManager()->GetParser<XmlDocument>(L"XML"))
										{
											if (auto xml = parser->Parse({ WString::Empty,fileAbsolutePath }, text, errors))
											{
												newContainingFolder = GetFolderPath(fileAbsolutePath);
												newFolderXml = xml->rootElement;
											}
										}
									}
									else
									{
										errors.Add(GuiResourceError({ {Ptr(this)},element->codeRange.start }, L"Failed to load file \"" + fileAbsolutePath + L"\"."));
									}
								}
								else if (contentAtt->value.value == L"Import")
								{
									auto importUri = XmlGetValue(element);
									folder->ImportFromUri(importUri, { {Ptr(this)},element->codeRange.start }, errors);
								}
								else
								{
									errors.Add(GuiResourceError({ {Ptr(this)},element->codeRange.start }, L"Folder's content attributes can only be \"Link\"."));
								}
							}
							if (folder->GetImportUri() == L"")
							{
								folder->LoadResourceFolderFromXml(delayLoadings, newContainingFolder, newFolderXml, errors);
							}
						}
						else
						{
							errors.Add(GuiResourceError({ {Ptr(this)},element->codeRange.start }, L"Duplicated resource folder name \"" + name + L"\"."));
						}
					}
				}
				else if (element->name.value.Length() <= 3 || element->name.value.Sub(0, 4) != L"ref.")
				{
					WString fileContentPath;
					WString fileAbsolutePath;
					if (Ptr<XmlAttribute> contentAtt = XmlGetAttribute(element, L"content"))
					{
						if (contentAtt->value.value == L"File")
						{
							fileContentPath = XmlGetValue(element);
							fileAbsolutePath = containingFolder + fileContentPath;
							if (name == L"")
							{
								name = GetFileName(fileAbsolutePath);
							}
						}
						else
						{
							errors.Add(GuiResourceError({ {Ptr(this)},element->codeRange.start }, L"File's content attributes can only be \"File\"."));
						}
					}

					auto item = Ptr(new GuiResourceItem);
					if (AddItem(name, item))
					{
						WString type = element->name.value;
						IGuiResourceTypeResolver* typeResolver = GetResourceResolverManager()->GetTypeResolver(type);
						IGuiResourceTypeResolver* preloadResolver = typeResolver;

						if (typeResolver)
						{
							if (!typeResolver->DirectLoadXml())
							{
								WString preloadType = typeResolver->IndirectLoad()->GetPreloadType();
								preloadResolver = GetResourceResolverManager()->GetTypeResolver(preloadType);
								if (!preloadResolver)
								{
									errors.Add(GuiResourceError({ {Ptr(this)}, element->codeRange.start }, L"[INTERNAL-ERROR] Unknown resource resolver \"" + preloadType + L"\" of resource type \"" + type + L"\"."));
								}
							}
						}
						else
						{
							errors.Add(GuiResourceError({ {Ptr(this)}, element->codeRange.start }, L"Unknown resource type \"" + type + L"\"."));
						}

						if (typeResolver && preloadResolver)
						{
							if (auto directLoad = preloadResolver->DirectLoadXml())
							{
								{
									Ptr<DescriptableObject> resource;
									if (fileAbsolutePath == L"")
									{
										resource = directLoad->ResolveResource(item, element, errors);
									}
									else
									{
										item->SetFileContentPath(fileContentPath, fileAbsolutePath);
										resource = directLoad->ResolveResource(item, fileAbsolutePath, errors);
									}
									item->SetContent(preloadResolver->GetType(), resource);
								}

								if (typeResolver != preloadResolver)
								{
									if (auto indirectLoad = typeResolver->IndirectLoad())
									{
										if (indirectLoad->IsDelayLoad())
										{
											DelayLoading delayLoading;
											delayLoading.type = type;
											delayLoading.workingDirectory = containingFolder;
											delayLoading.preloadResource = item;
											delayLoadings.Add(delayLoading);
										}
										else if (item->GetContent())
										{
											auto resource = indirectLoad->ResolveResource(item, 0, errors);
											item->SetContent(typeResolver->GetType(), resource);
										}
									}
									else
									{
										item->SetContent(typeResolver->GetType(), nullptr);
										errors.Add(GuiResourceError({ {Ptr(this)},element->codeRange.start }, L"[INTERNAL-ERROR] Resource type \"" + typeResolver->GetType() + L"\" is not a indirect load resource type."));									}
								}
							}
							else
							{
								errors.Add(GuiResourceError({ {Ptr(this)},element->codeRange.start }, L"[INTERNAL-ERROR] Resource type \"" + preloadResolver->GetType() + L"\" is not a direct load resource type."));
							}
						}

						if (!item->GetContent())
						{
							RemoveItem(name);
						}
					}
					else
					{
						errors.Add(GuiResourceError({ {Ptr(this)},element->codeRange.start }, L"Duplicated resource item name \"" + name + L"\"."));
					}
				}
			}
		}

		void GuiResourceFolder::SaveResourceFolderToXml(Ptr<glr::xml::XmlElement> xmlParent)
		{
			for (auto item : items.Values())
			{
				auto resolver = GetResourceResolverManager()->GetTypeResolver(item->GetTypeName());
				if (resolver->XmlSerializable())
				{
					auto attName = Ptr(new XmlAttribute);
					attName->name.value = L"name";
					attName->value.value = item->GetName();

					if (item->GetFileContentPath() == L"")
					{
						Ptr<XmlElement> xmlElement;

						if (auto directLoad = resolver->DirectLoadXml())
						{
							xmlElement = directLoad->Serialize(item, item->GetContent());
						}
						else if (auto indirectLoad = resolver->IndirectLoad())
						{
							if (auto preloadResolver = GetResourceResolverManager()->GetTypeResolver(indirectLoad->GetPreloadType()))
							{
								if (auto directLoad = preloadResolver->DirectLoadXml())
								{
									if (auto resource = indirectLoad->Serialize(item, item->GetContent()))
									{
										xmlElement = directLoad->Serialize(item, resource);
										xmlElement->name.value = resolver->GetType();
									}
								}
							}
						}

						if (xmlElement)
						{
							xmlElement->attributes.Add(attName);
							xmlParent->subNodes.Add(xmlElement);
						}
					}
					else
					{
						auto xmlElement = Ptr(new XmlElement);
						xmlElement->name.value = item->GetTypeName();
						xmlParent->subNodes.Add(xmlElement);

						auto attContent = Ptr(new XmlAttribute);
						attContent->name.value = L"content";
						attContent->value.value = L"File";
						xmlElement->attributes.Add(attContent);

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

			for (auto folder : folders.Values())
			{
				auto attName = Ptr(new XmlAttribute);
				attName->name.value = L"name";
				attName->value.value = folder->GetName();

				auto xmlFolder = Ptr(new XmlElement);
				xmlFolder->name.value = L"Folder";
				xmlFolder->attributes.Add(attName);
				xmlParent->subNodes.Add(xmlFolder);
				
				if (folder->GetImportUri() != L"")
				{
					auto attContent = Ptr(new XmlAttribute);
					attContent->name.value = L"content";
					attContent->value.value = L"Import";
					xmlFolder->attributes.Add(attContent);

					auto xmlText = Ptr(new XmlText);
					xmlText->content.value = folder->GetImportUri();
					xmlFolder->subNodes.Add(xmlText);
				}
				else if (folder->GetFileContentPath() != L"")
				{
					auto attContent = Ptr(new XmlAttribute);
					attContent->name.value = L"content";
					attContent->value.value = L"Link";
					xmlFolder->attributes.Add(attContent);

					auto xmlText = Ptr(new XmlText);
					xmlText->content.value = folder->GetFileContentPath();
					xmlFolder->subNodes.Add(xmlText);
				}
				else
				{
					folder->SaveResourceFolderToXml(xmlFolder);
				}
			}
		}

		void GuiResourceFolder::CollectTypeNames(collections::List<WString>& typeNames)
		{
			if (importUri != L"") return;
			for (auto item : items.Values())
			{
				if (!typeNames.Contains(item->GetTypeName()))
				{
					typeNames.Add(item->GetTypeName());
				}
			}
			for (auto folder : folders.Values())
			{
				folder->CollectTypeNames(typeNames);
			}
		}

		void GuiResourceFolder::LoadResourceFolderFromBinary(DelayLoadingList& delayLoadings, stream::internal::ContextFreeReader& reader, collections::List<WString>& typeNames, GuiResourceError::List& errors)
		{
			vint count = 0;
			reader << count;
			for (vint i = 0; i < count; i++)
			{
				vint typeName = 0;
				WString name;
				reader << typeName << name;

				auto resolver = GetResourceResolverManager()->GetTypeResolver(typeNames[typeName]);
				auto item = Ptr(new GuiResourceItem);
				if(AddItem(name, item))
				{
					WString type = typeNames[typeName];
					IGuiResourceTypeResolver* typeResolver = GetResourceResolverManager()->GetTypeResolver(type);
					IGuiResourceTypeResolver* preloadResolver = typeResolver;

					if(typeResolver)
					{
						if (!typeResolver->DirectLoadStream())
						{
							WString preloadType = typeResolver->IndirectLoad()->GetPreloadType();
							if (preloadType != L"")
							{
								preloadResolver = GetResourceResolverManager()->GetTypeResolver(preloadType);
								if (!preloadResolver)
								{
									errors.Add(GuiResourceError({ item }, L"[INTERNAL-ERROR] Unknown resource resolver \"" + preloadType + L"\" of resource type \"" + type + L"\"."));
								}
							}
						}
					}
					else
					{
						errors.Add(GuiResourceError({ item }, L"[BINARY] Unknown resource type \"" + type + L"\"."));
					}

					if(typeResolver && preloadResolver)
					{
						if (auto directLoad = preloadResolver->DirectLoadStream())
						{
							{
								auto resource = directLoad->ResolveResourcePrecompiled(item, reader.input, errors);
								item->SetContent(preloadResolver->GetType(), resource);
							}

							if (typeResolver != preloadResolver)
							{
								if (auto indirectLoad = typeResolver->IndirectLoad())
								{
									if(indirectLoad->IsDelayLoad())
									{
										DelayLoading delayLoading;
										delayLoading.type = type;
										delayLoading.preloadResource = item;
										delayLoadings.Add(delayLoading);
									}
									else if(item->GetContent())
									{
										auto resource = indirectLoad->ResolveResource(item, nullptr, errors);
										item->SetContent(typeResolver->GetType(), resource);
									}
								}
								else
								{
									item->SetContent(typeResolver->GetType(), nullptr);
									errors.Add(GuiResourceError({ item }, L"[INTERNAL-ERROR] Resource type \"" + typeResolver->GetType() + L"\" is not a indirect load resource type."));
								}
							}
						}
						else
						{
							errors.Add(GuiResourceError({ item }, L"[INTERNAL-ERROR] Resource type \"" + preloadResolver->GetType() + L"\" is not a direct load resource type."));
						}
					}

					if(!item->GetContent())
					{
						RemoveItem(name);
					}
				}
				else
				{
					errors.Add(GuiResourceError({Ptr(this)}, L"[BINARY] Duplicated resource item name \"" + name + L"\"."));
				}
			}

			reader << count;
			for (vint i = 0; i < count; i++)
			{
				WString name, importUri;
				reader << name << importUri;

				auto folder = Ptr(new GuiResourceFolder);
				if (importUri == L"")
				{
					folder->LoadResourceFolderFromBinary(delayLoadings, reader, typeNames, errors);
				}
				else
				{
					folder->ImportFromUri(importUri, { {Ptr(this)},{0,0} }, errors);
				}
				AddFolder(name, folder);
			}
		}

		void GuiResourceFolder::SaveResourceFolderToBinary(stream::internal::ContextFreeWriter& writer, collections::List<WString>& typeNames)
		{
			typedef Tuple<vint, WString, IGuiResourceTypeResolver_DirectLoadStream*, Ptr<GuiResourceItem>, Ptr<DescriptableObject>> ItemTuple;
			List<ItemTuple> itemTuples;

			for (auto item : items.Values())
			{
				auto resolver = GetResourceResolverManager()->GetTypeResolver(item->GetTypeName());
				if (resolver->StreamSerializable())
				{
					vint typeName = typeNames.IndexOf(item->GetTypeName());
					WString name = item->GetName();
				
					if (auto directLoad = resolver->DirectLoadStream())
					{
						itemTuples.Add(ItemTuple(typeName, name, directLoad, item, item->GetContent()));
					}
					else if (auto indirectLoad = resolver->IndirectLoad())
					{
						if (auto preloadResolver = GetResourceResolverManager()->GetTypeResolver(indirectLoad->GetPreloadType()))
						{
							if (auto directLoad = preloadResolver->DirectLoadStream())
							{
								if (auto resource = indirectLoad->Serialize(item, item->GetContent()))
								{
									itemTuples.Add(ItemTuple(typeName, name, directLoad, item, resource));
								}
							}
						}
					}
				}
			}

			vint count = itemTuples.Count();
			writer << count;
			for (auto [typeName, name, directLoad, resource, content] : itemTuples)
			{
				writer << typeName << name;
				directLoad->SerializePrecompiled(resource, content, writer.output);
			}

			count = folders.Count();
			writer << count;
			for (auto folder : folders.Values())
			{
				WString name = folder->GetName();
				WString importUri = folder->GetImportUri();
				writer << name << importUri;
				if (importUri == L"")
				{
					folder->SaveResourceFolderToBinary(writer, typeNames);
				}
			}
		}

		void GuiResourceFolder::PrecompileResourceFolder(GuiResourcePrecompileContext& context, IGuiResourcePrecompileCallback* callback, GuiResourceError::List& errors)
		{
			if (importUri != L"") return;
			for (auto item : items.Values())
			{
				auto typeResolver = GetResourceResolverManager()->GetTypeResolver(item->GetTypeName());
				if (auto precompile = typeResolver->Precompile())
				{
					if (precompile->GetPrecompilePassSupport(context.passIndex) == IGuiResourceTypeResolver_Precompile::PerResource)
					{
						if (callback)
						{
							callback->OnPerResource(context.passIndex, item);
						}
						precompile->PerResourcePrecompile(item, context, errors);
					}
				}
			}

			for (auto folder : folders.Values())
			{
				folder->PrecompileResourceFolder(context, callback, errors);
			}
		}

		void GuiResourceFolder::InitializeResourceFolder(GuiResourceInitializeContext& context, GuiResourceError::List& errors)
		{
			if (importUri != L"") return;
			for (auto item : items.Values())
			{
				auto typeResolver = GetResourceResolverManager()->GetTypeResolver(item->GetTypeName());
				if (auto initialize = typeResolver->Initialize())
				{
					if (initialize->GetInitializePassSupport(context.passIndex))
					{
						initialize->Initialize(item, context, errors);
					}
				}
			}

			for (auto folder : folders.Values())
			{
				folder->InitializeResourceFolder(context, errors);
			}
		}

		void GuiResourceFolder::ImportFromUri(const WString& uri, GuiResourceTextPos position, GuiResourceError::List& errors)
		{
			SetImportUri(uri);
			if (importUri.Length() == 0 || importUri[importUri.Length() - 1] != L'/')
			{
				errors.Add(GuiResourceError(position, L"Path of imported folder should ends with L\"/\"."));
			}
			else
			{
				WString protocol, path;
				if (IsResourceUrl(importUri, protocol, path))
				{
					if (protocol == L"import-res")
					{
						auto factory = GetResourceResolverManager()->GetPathResolverFactory(protocol);
						auto resolver = factory->CreateResolver(nullptr, L"");
						if (auto sourceFolder = resolver->ResolveResource(path).Cast<GuiResourceFolder>())
						{
							CopyFrom(items, sourceFolder->items);
							CopyFrom(folders, sourceFolder->folders);
						}
						else
						{
							errors.Add(GuiResourceError(position, L"Path of imported folder does not exist: \"" + importUri + L"\"."));
						}
					}
					else
					{
						errors.Add(GuiResourceError(position, L"Path of imported folder should begin with \"import-res://\"."));
					}
				}
				else
				{
					errors.Add(GuiResourceError(position, L"Invalid path of imported folder : \"" + importUri + L"\"."));
				}
			}
		}

		GuiResourceFolder::GuiResourceFolder()
		{
		}

		GuiResourceFolder::~GuiResourceFolder()
		{
		}

		const WString& GuiResourceFolder::GetImportUri()
		{
			return importUri;
		}

		void GuiResourceFolder::SetImportUri(const WString& uri)
		{
			importUri = uri;
		}

		const GuiResourceFolder::ItemList& GuiResourceFolder::GetItems()
		{
			return items.Values();
		}

		Ptr<GuiResourceItem> GuiResourceFolder::GetItem(const WString& name)
		{
			vint index=items.Keys().IndexOf(name);
			return index == -1 ? nullptr : items.Values().Get(index);
		}

		bool GuiResourceFolder::AddItem(const WString& name, Ptr<GuiResourceItem> item)
		{
			if (item->GetParent() != 0 || items.Keys().Contains(name)) return false;
			items.Add(name, item);
			item->parent = this;
			item->name = name;
			return true;
		}

		Ptr<GuiResourceItem> GuiResourceFolder::RemoveItem(const WString& name)
		{
			Ptr<GuiResourceItem> item = GetItem(name);
			if (!item) return 0;
			items.Remove(name);
			item->parent = nullptr;
			item->name = L"";
			return item;
		}

		void GuiResourceFolder::ClearItems()
		{
			items.Clear();
		}

		const GuiResourceFolder::FolderList& GuiResourceFolder::GetFolders()
		{
			return folders.Values();
		}

		Ptr<GuiResourceFolder> GuiResourceFolder::GetFolder(const WString& name)
		{
			vint index=folders.Keys().IndexOf(name);
			return index == -1 ? nullptr : folders.Values().Get(index);
		}

		bool GuiResourceFolder::AddFolder(const WString& name, Ptr<GuiResourceFolder> folder)
		{
			if (folder->GetParent() != 0 || folders.Keys().Contains(name)) return false;
			folders.Add(name, folder);
			folder->parent = this;
			folder->name = name;
			return true;
		}

		Ptr<GuiResourceFolder> GuiResourceFolder::RemoveFolder(const WString& name)
		{
			Ptr<GuiResourceFolder> folder = GetFolder(name);
			if (!folder) return 0;
			folders.Remove(name);
			folder->parent = nullptr;
			folder->name = L"";
			return folder;
		}

		void GuiResourceFolder::ClearFolders()
		{
			folders.Clear();
		}

		Ptr<DescriptableObject> GuiResourceFolder::GetValueByPath(const WString& path)
		{
			const wchar_t* buffer=path.Buffer();
			const wchar_t* index=wcschr(buffer, L'\\');
			if(!index) index=wcschr(buffer, '/');

			if(index)
			{
				WString name=path.Sub(0, index-buffer);
				Ptr<GuiResourceFolder> folder=GetFolder(name);
				if(folder)
				{
					vint start=index-buffer+1;
					return folder->GetValueByPath(path.Sub(start, path.Length()-start));
				}
			}
			else
			{
				Ptr<GuiResourceItem> item=GetItem(path);
				if(item)
				{
					return item->GetContent();
				}
			}
			return 0;
		}

		Ptr<GuiResourceFolder> GuiResourceFolder::GetFolderByPath(const WString& path)
		{
			const wchar_t* buffer=path.Buffer();
			const wchar_t* index=wcschr(buffer, L'\\');
			if(!index) index=wcschr(buffer, '/');
			if(!index) return 0;

			WString name=path.Sub(0, index-buffer);
			Ptr<GuiResourceFolder> folder=GetFolder(name);

			if(index-buffer==path.Length()-1)
			{
				return folder;
			}

			if(folder)
			{
				vint start=index-buffer+1;
				return folder->GetFolderByPath(path.Sub(start, path.Length()-start));
			}

			return 0;
		}

		bool GuiResourceFolder::CreateValueByPath(const WString& path, const WString& typeName, Ptr<DescriptableObject> value)
		{
			const wchar_t* buffer = path.Buffer();
			const wchar_t* index = wcschr(buffer, L'\\');
			if (!index) index = wcschr(buffer, '/');

			if(index)
			{
				WString name = path.Sub(0, index - buffer);
				Ptr<GuiResourceFolder> folder = GetFolder(name);
				if (!folder)
				{
					folder = Ptr(new GuiResourceFolder);
					AddFolder(name, folder);
				}
				vint start = index - buffer + 1;
				return folder->CreateValueByPath(path.Sub(start, path.Length() - start), typeName, value);
			}
			else
			{
				if(GetItem(path))
				{
					return false;
				}

				auto item = Ptr(new GuiResourceItem);
				item->SetContent(typeName, value);
				return AddItem(path, item);
			}
		}

/***********************************************************************
GuiResourceMetadata
***********************************************************************/

		void GuiResourceMetadata::LoadFromXml(Ptr<glr::xml::XmlDocument> xml, GuiResourceLocation location, GuiResourceError::List& errors)
		{
			auto attrName = XmlGetAttribute(xml->rootElement, L"Name");
			auto attrVersion = XmlGetAttribute(xml->rootElement, L"Version");
			if (!attrName || !attrVersion)
			{
				errors.Add(GuiResourceError(location, L"[INTERNAL-ERROR] Resource metadata lacks of Name or Version attribute."));
				return;
			}
			name = attrName->value.value;
			version = attrVersion->value.value;
			dependencies.Clear();

			if (auto xmlDeps = XmlGetElement(xml->rootElement, L"Dependencies"))
			{
				for (auto xmlDep : XmlGetElements(xmlDeps, L"Resource"))
				{
					auto attrDep = XmlGetAttribute(xmlDep, L"Name");
					if (!attrDep)
					{
						errors.Add(GuiResourceError(location, L"[INTERNAL-ERROR] Resource dependency lacks of Name attribute."));
					}
					dependencies.Add(attrDep->value.value);
				}
			}
		}

		Ptr<glr::xml::XmlDocument> GuiResourceMetadata::SaveToXml()
		{
			auto root = Ptr(new XmlElement);
			root->name.value = L"ResourceMetadata";
			{
				auto attr = Ptr(new XmlAttribute);
				attr->name.value = L"Name";
				attr->value.value = name;
				root->attributes.Add(attr);
			}
			{
				auto attr = Ptr(new XmlAttribute);
				attr->name.value = L"Version";
				attr->value.value = version;
				root->attributes.Add(attr);
			}
			{
				auto xmlDeps = Ptr(new XmlElement);
				xmlDeps->name.value = L"Dependencies";
				root->subNodes.Add(xmlDeps);

				for (auto dep : dependencies)
				{
					auto xmlDep = Ptr(new XmlElement);
					xmlDep->name.value = L"Resource";
					xmlDeps->subNodes.Add(xmlDep);
					{
						auto attr = Ptr(new XmlAttribute);
						attr->name.value = L"Name";
						attr->value.value = dep;
						xmlDep->attributes.Add(attr);
					}
				}
			}

			auto doc = Ptr(new XmlDocument);
			doc->rootElement = root;
			return doc;
		}

/***********************************************************************
GuiResource
***********************************************************************/

		const wchar_t* GuiResource::CurrentVersionString = L"1.0";

		void GuiResource::ProcessDelayLoading(Ptr<GuiResource> resource, DelayLoadingList& delayLoadings, GuiResourceError::List& errors)
		{
			for (auto delay : delayLoadings)
			{
				WString type = delay.type;
				WString folder = delay.workingDirectory;
				Ptr<GuiResourceItem> item = delay.preloadResource;

				if (auto typeResolver = GetResourceResolverManager()->GetTypeResolver(type))
				{
					if (auto indirectLoad = typeResolver->IndirectLoad())
					{
						if (item->GetContent())
						{
							auto pathResolver = Ptr(new GuiResourcePathResolver(resource, folder));
							Ptr<DescriptableObject> resource = indirectLoad->ResolveResource(item, pathResolver, errors);
							if (resource)
							{
								item->SetContent(typeResolver->GetType(), resource);
							}
						}
					}
					else
					{
						errors.Add(GuiResourceError({ item }, L"[INTERNAL-ERROR] Resource type \"" + type + L"\" is not a indirect load resource type."));
					}
				}
				else
				{
					errors.Add(GuiResourceError({ item }, L"[INTERNAL-ERROR] Unknown resource type \"" + type + L"\"."));
				}
			}
		}

		GuiResource::GuiResource()
		{
			metadata = Ptr(new GuiResourceMetadata);
			metadata->version = WString::Unmanaged(CurrentVersionString);
		}

		GuiResource::~GuiResource()
		{
		}

		Ptr<GuiResourceMetadata> GuiResource::GetMetadata()
		{
			return metadata;
		}

		WString GuiResource::GetWorkingDirectory()
		{
			return workingDirectory;
		}

		Ptr<GuiResource> GuiResource::LoadFromXml(Ptr<glr::xml::XmlDocument> xml, const WString& filePath, const WString& workingDirectory, GuiResourceError::List& errors)
		{
			auto resource = Ptr(new GuiResource);
			resource->SetFileContentPath(filePath, filePath);
			resource->workingDirectory = workingDirectory;
			DelayLoadingList delayLoadings;
			resource->LoadResourceFolderFromXml(delayLoadings, resource->workingDirectory, xml->rootElement, errors);

			ProcessDelayLoading(resource, delayLoadings, errors);
			return resource;
		}

		Ptr<GuiResource> GuiResource::LoadFromXml(const WString& filePath, GuiResourceError::List& errors)
		{
			Ptr<XmlDocument> xml;
			if(auto parser=GetParserManager()->GetParser<XmlDocument>(L"XML"))
			{
				WString text;
				if(LoadTextFile(filePath, text))
				{
					xml = parser->Parse({ WString::Empty,filePath }, text, errors);
				}
				else
				{
					errors.Add(GuiResourceError({ WString::Empty,filePath }, L"Failed to load file \"" + filePath + L"\"."));
				}
			}
			if(xml)
			{
				return LoadFromXml(xml, filePath, GetFolderPath(filePath), errors);
			}
			return 0;
		}

		Ptr<glr::xml::XmlDocument> GuiResource::SaveToXml()
		{
			auto xmlRoot = Ptr(new XmlElement);
			xmlRoot->name.value = L"Resource";
			SaveResourceFolderToXml(xmlRoot);

			auto doc = Ptr(new XmlDocument);
			doc->rootElement = xmlRoot;
			return doc;
		}

		Ptr<GuiResource> GuiResource::LoadPrecompiledBinary(stream::IStream& binaryStream, GuiResourceError::List& errors)
		{
			stream::internal::ContextFreeReader reader(binaryStream);
			auto resource = Ptr(new GuiResource);
			{
				WString metadata;
				reader << metadata;

				auto parser = GetParserManager()->GetParser<XmlDocument>(L"XML");
				auto xmlMetadata = parser->Parse({ resource }, metadata, errors);
				if (!xmlMetadata) return nullptr;

				resource->metadata->LoadFromXml(xmlMetadata, { resource }, errors);
				if (errors.Count() != 0) return nullptr;

				if (resource->metadata->version != CurrentVersionString)
				{
					errors.Add(GuiResourceError({ resource }, L"Only resource binary of version \"" + WString::Unmanaged(CurrentVersionString) + L"\" is accepted. Please recompile the resource before loading it."));
					return nullptr;
				}
			}

			List<WString> typeNames;
			reader << typeNames;

			DelayLoadingList delayLoadings;
			resource->LoadResourceFolderFromBinary(delayLoadings, reader, typeNames, errors);

			ProcessDelayLoading(resource, delayLoadings, errors);
			return resource;
		}

		Ptr<GuiResource> GuiResource::LoadPrecompiledBinary(stream::IStream& binaryStream)
		{
			GuiResourceError::List errors;
			auto resource = LoadPrecompiledBinary(binaryStream, errors);
			CHECK_ERROR(errors.Count() == 0, L"GuiResource::LoadPrecompiledBinary(IStream&)#There are errors.");
			return resource;
		}

		void GuiResource::SavePrecompiledBinary(stream::IStream& binaryStream)
		{
			stream::internal::ContextFreeWriter writer(binaryStream);
			{
				auto xmlMetadata = metadata->SaveToXml();
				WString xml = GenerateToStream([&](StreamWriter& writer)
				{
					XmlPrint(xmlMetadata, writer);
				});
				writer << xml;
			}
			List<WString> typeNames;
			CollectTypeNames(typeNames);
			writer << typeNames;
			SaveResourceFolderToBinary(writer, typeNames);
		}

		Ptr<GuiResourceFolder> GuiResource::Precompile(GuiResourceCpuArchitecture targetCpuArchitecture, IGuiResourcePrecompileCallback* callback, GuiResourceError::List& errors)
		{
			if (targetCpuArchitecture == GuiResourceCpuArchitecture::Unspecified)
			{
#ifdef VCZH_64
	targetCpuArchitecture = GuiResourceCpuArchitecture::x64;
#else
	targetCpuArchitecture = GuiResourceCpuArchitecture::x86;
#endif
			}

			if (GetFolder(L"Precompiled"))
			{
				errors.Add(GuiResourceError({Ptr(this)}, L"A precompiled resource cannot be compiled again."));
				return nullptr;
			}

			GuiResourcePrecompileContext context;
			context.targetCpuArchitecture = targetCpuArchitecture;
			context.compilerCallback = callback ? callback->GetCompilerCallback() : nullptr;
			context.rootResource = this;
			context.resolver = Ptr(new GuiResourcePathResolver(Ptr(this), workingDirectory));
			context.targetFolder = Ptr(new GuiResourceFolder);
			
			auto manager = GetResourceResolverManager();
			List<WString> resolvers;
			for (vint i = 0; i <= IGuiResourceTypeResolver_Precompile::Everything_Max; i++)
			{
				context.passIndex = i;
				{
					manager->GetPerResourceResolverNames(i, resolvers);
					if (resolvers.Count() > 0)
					{
						PrecompileResourceFolder(context, callback, errors);
					}
				}
				{
					manager->GetPerPassResolverNames(i, resolvers);
					if (resolvers.Count() > 0)
					{
						if (callback)
						{
							callback->OnPerPass(i);
						}
						for (auto name : resolvers)
						{
							auto resolver = manager->GetTypeResolver(name);
							resolver->Precompile()->PerPassPrecompile(context, errors);
						}
					}
				}
				if (errors.Count() > 0)
				{
					return context.targetFolder;
				}
			}
			AddFolder(L"Precompiled", context.targetFolder);
			return context.targetFolder;
		}

		void GuiResource::Initialize(GuiResourceUsage usage, GuiResourceError::List& errors)
		{
			auto precompiledFolder = GetFolder(L"Precompiled");
			if (!precompiledFolder)
			{
				CHECK_FAIL(L"GuiResource::Initialize()#Cannot initialize a non-precompiled resource.");
				return;
			}
			
			GuiResourceInitializeContext context;
			context.rootResource = this;
			context.resolver = Ptr(new GuiResourcePathResolver(Ptr(this), workingDirectory));
			context.targetFolder = precompiledFolder;
			context.usage = usage;

			for (vint i = 0; i <= IGuiResourceTypeResolver_Initialize::Everything_Max; i++)
			{
				context.passIndex = i;
				InitializeResourceFolder(context, errors);
			}
		}

		Ptr<DocumentModel> GuiResource::GetDocumentByPath(const WString& path)
		{
			Ptr<DocumentModel> result=GetValueByPath(path).Cast<DocumentModel>();
			if (!result)
			{
				throw ArgumentException(L"Path not exists: " + path, L"GuiResource::GetDocumentByPath", L"path");
			}
			return result;
		}

		Ptr<GuiImageData> GuiResource::GetImageByPath(const WString& path)
		{
			Ptr<GuiImageData> result=GetValueByPath(path).Cast<GuiImageData>();
			if (!result)
			{
				throw ArgumentException(L"Path not exists: " + path, L"GuiResource::GetImageByPath", L"path");
			}
			return result;
		}

		Ptr<glr::xml::XmlDocument> GuiResource::GetXmlByPath(const WString& path)
		{
			Ptr<XmlDocument> result=GetValueByPath(path).Cast<XmlDocument>();
			if (!result)
			{
				throw ArgumentException(L"Path not exists: " + path, L"GuiResource::GetXmlByPath", L"path");
			}
			return result;
		}

		WString GuiResource::GetStringByPath(const WString& path)
		{
			Ptr<GuiTextData> result=GetValueByPath(path).Cast<GuiTextData>();
			if (!result)
			{
				throw ArgumentException(L"Path not exists: " + path, L"GuiResource::GetStringByPath", L"path");
			}
			return result->GetText();
		}

/***********************************************************************
GuiResourcePathResolver
***********************************************************************/

		GuiResourcePathResolver::GuiResourcePathResolver(Ptr<GuiResource> _resource, const WString& _workingDirectory)
			:resource(_resource)
			,workingDirectory(_workingDirectory)
		{
		}

		GuiResourcePathResolver::~GuiResourcePathResolver()
		{
		}

		Ptr<DescriptableObject> GuiResourcePathResolver::ResolveResource(const WString& protocol, const WString& path)
		{
			Ptr<IGuiResourcePathResolver> resolver;
			vint index=resolvers.Keys().IndexOf(protocol);
			if(index==-1)
			{
				IGuiResourcePathResolverFactory* factory=GetResourceResolverManager()->GetPathResolverFactory(protocol);
				if(factory)
				{
					resolver=factory->CreateResolver(resource, workingDirectory);
				}
				resolvers.Add(protocol, resolver);
			}
			else
			{
				resolver=resolvers.Values()[index];
			}

			if(resolver)
			{
				return resolver->ResolveResource(path);
			}
			else
			{
				return 0;
			}
		}

/***********************************************************************
GuiResourcePathResResolver
***********************************************************************/

		class GuiResourcePathResResolver : public Object, public IGuiResourcePathResolver
		{
		protected:
			Ptr<GuiResource>		resource;

		public:
			GuiResourcePathResResolver(Ptr<GuiResource> _resource)
				:resource(_resource)
			{
			}

			Ptr<DescriptableObject> ResolveResource(const WString& path)
			{
				if (resource)
				{
					if (path.Length() > 0)
					{
						switch (path[path.Length() - 1])
						{
						case L'\\':case L'/':
							return resource->GetFolderByPath(path);
						default:
							return resource->GetValueByPath(path);
						}
					}
				}
				return nullptr;
			}

			class Factory : public Object, public IGuiResourcePathResolverFactory
			{
			public:
				WString GetProtocol()override
				{
					return L"res";
				}

				Ptr<IGuiResourcePathResolver> CreateResolver(Ptr<GuiResource> resource, const WString& workingDirectory)override
				{
					return Ptr(new GuiResourcePathResResolver(resource));
				}
			};
		};

/***********************************************************************
GuiImportResourcePathResResolver
***********************************************************************/

		class GuiImportResourcePathResResolver : public Object, public IGuiResourcePathResolver
		{
		public:
			GuiImportResourcePathResResolver()
			{
			}

			Ptr<DescriptableObject> ResolveResource(const WString& path)
			{
				const wchar_t* buffer = path.Buffer();
				const wchar_t* d1 = wcschr(buffer, L'\\');
				const wchar_t* d2 = wcschr(buffer, L'/');
				const wchar_t* d =
					d1 == nullptr&&d2 == nullptr ? nullptr :
					d1 == nullptr ? d2 :
					d2 == nullptr ? d1 :
					d1 < d2 ? d1 : d2;

				if (!d) return nullptr;
				WString resourceName = WString::CopyFrom(buffer, d - buffer);
				WString resourcePath(path.Right(path.Length() - resourceName.Length() - 1));
				if (auto resource = GetResourceManager()->GetResource(resourceName))
				{
					switch (path[path.Length() - 1])
					{
					case L'\\':case L'/':
						return resource->GetFolderByPath(resourcePath);
					default:
						return resource->GetValueByPath(resourcePath);
					}
				}
				return nullptr;
			}

			class Factory : public Object, public IGuiResourcePathResolverFactory
			{
			public:
				WString GetProtocol()override
				{
					return L"import-res";
				}

				Ptr<IGuiResourcePathResolver> CreateResolver(Ptr<GuiResource> resource, const WString& workingDirectory)override
				{
					return Ptr(new GuiImportResourcePathResResolver);
				}
			};
		};

/***********************************************************************
IGuiResourceResolverManager
***********************************************************************/

		IGuiResourceResolverManager* resourceResolverManager=0;

		IGuiResourceResolverManager* GetResourceResolverManager()
		{
			return resourceResolverManager;
		}

		class GuiResourceResolverManager : public Object, public IGuiResourceResolverManager, public IGuiPlugin
		{
			typedef Dictionary<WString, Ptr<IGuiResourcePathResolverFactory>>			PathFactoryMap;
			typedef Dictionary<WString, Ptr<IGuiResourceTypeResolver>>					TypeResolverMap;
			typedef Group<vint, WString>												ResolverGroup;
		protected:
			PathFactoryMap				pathFactories;
			TypeResolverMap				typeResolvers;
			ResolverGroup				perResourceResolvers;
			ResolverGroup				perPassResolvers;

		public:
			
			GUI_PLUGIN_NAME(GacUI_Res_ResourceResolver)
			{
			}

			void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerUnrelatedPlugins)
				{
					globalStringKeyManager = new GlobalStringKeyManager();
					globalStringKeyManager->InitializeConstants();

					resourceResolverManager = this;
					SetPathResolverFactory(Ptr(new GuiResourcePathResResolver::Factory));
					SetPathResolverFactory(Ptr(new GuiImportResourcePathResResolver::Factory));
				}
			}

			void Unload(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerUnrelatedPlugins)
				{
					delete globalStringKeyManager;
					globalStringKeyManager = nullptr;
					resourceResolverManager = nullptr;
				}
			}

			IGuiResourcePathResolverFactory* GetPathResolverFactory(const WString& protocol)override
			{
				vint index=pathFactories.Keys().IndexOf(protocol);
				return index==-1?0:pathFactories.Values()[index].Obj();
			}

			bool SetPathResolverFactory(Ptr<IGuiResourcePathResolverFactory> factory)override
			{
				if(pathFactories.Keys().Contains(factory->GetProtocol())) return false;
				pathFactories.Add(factory->GetProtocol(), factory);
				return true;
			}

			IGuiResourceTypeResolver* GetTypeResolver(const WString& type)override
			{
				vint index=typeResolvers.Keys().IndexOf(type);
				return index==-1?0:typeResolvers.Values()[index].Obj();
			}

			bool SetTypeResolver(Ptr<IGuiResourceTypeResolver> resolver)override
			{
				if(typeResolvers.Keys().Contains(resolver->GetType())) return false;
				typeResolvers.Add(resolver->GetType(), resolver);

				if (auto precompile = resolver->Precompile())
				{
					for (vint i = 0; i <= IGuiResourceTypeResolver_Precompile::Everything_Max; i++)
					{
						switch (precompile->GetPrecompilePassSupport(i))
						{
						case IGuiResourceTypeResolver_Precompile::PerResource:
							perResourceResolvers.Add(i, resolver->GetType());
							break;
						case IGuiResourceTypeResolver_Precompile::PerPass:
							perPassResolvers.Add(i, resolver->GetType());
							break;
						default:;
						}
					}
				}

				return true;
			}

			void GetPerResourceResolverNames(vint passIndex, collections::List<WString>& names)override
			{
				names.Clear();
				vint index = perResourceResolvers.Keys().IndexOf(passIndex);
				if (index != -1)
				{
					CopyFrom(names, perResourceResolvers.GetByIndex(index));
				}
			}

			void GetPerPassResolverNames(vint passIndex, collections::List<WString>& names)override
			{
				names.Clear();
				vint index = perPassResolvers.Keys().IndexOf(passIndex);
				if (index != -1)
				{
					CopyFrom(names, perPassResolvers.GetByIndex(index));
				}
			}
		};
		GUI_REGISTER_PLUGIN(GuiResourceResolverManager)

/***********************************************************************
Helpers
***********************************************************************/

		void DecompressStream(const char** buffer, bool decompress, vint rows, vint block, vint remain, stream::IStream& outputStream)
		{
			if (decompress)
			{
				MemoryStream compressedStream;
				DecompressStream(buffer, false, rows, block, remain, compressedStream);
				compressedStream.SeekFromBegin(0);
				DecompressStream(compressedStream, outputStream);
			}
			else
			{
				for (vint i = 0; i < rows; i++)
				{
					vint size = (i == rows - 1 && remain > 0) ? remain : block;
					outputStream.Write((void*)buffer[i], size);
				}
			}
		}
	}
}


/***********************************************************************
.\RESOURCES\GUIRESOURCEMANAGER.CPP
***********************************************************************/

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

/***********************************************************************
Class Name Record (ClassNameRecord)
***********************************************************************/

		class GuiResourceClassNameRecordTypeResolver
			: public Object
			, public IGuiResourceTypeResolver
			, private IGuiResourceTypeResolver_DirectLoadStream
		{
		public:
			WString GetType()override
			{
				return L"ClassNameRecord";
			}

			bool XmlSerializable()override
			{
				return false;
			}

			bool StreamSerializable()override
			{
				return true;
			}

			IGuiResourceTypeResolver_DirectLoadStream* DirectLoadStream()override
			{
				return this;
			}

			void SerializePrecompiled(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content, stream::IStream& binaryStream)override
			{
				if (auto obj = content.Cast<GuiResourceClassNameRecord>())
				{
					internal::ContextFreeWriter writer(binaryStream);
					writer << obj->classNames;
				}
			}

			Ptr<DescriptableObject> ResolveResourcePrecompiled(Ptr<GuiResourceItem> resource, stream::IStream& binaryStream, GuiResourceError::List& errors)override
			{
				internal::ContextFreeReader reader(binaryStream);

				auto obj = Ptr(new GuiResourceClassNameRecord);
				reader << obj->classNames;
				return obj;
			}
		};

/***********************************************************************
IGuiInstanceResourceManager
***********************************************************************/

		IGuiResourceManager* resourceManager = nullptr;

		IGuiResourceManager* GetResourceManager()
		{
			return resourceManager;
		}

		class GuiResourceManager : public Object, public IGuiResourceManager, public IGuiPlugin
		{
		protected:
			typedef Dictionary<WString, Ptr<GuiResource>>					ResourceMap;

			List<Ptr<GuiResource>>					anonymousResources;
			ResourceMap								resources;
			ResourceMap								instanceResources;

			class PendingResource : public Object
			{
			public:
				Ptr<GuiResourceMetadata>			metadata;
				GuiResourceUsage					usage;
				MemoryStream						memoryStream;
				SortedList<WString>					dependencies;

				Ptr<GuiResource> LoadResource()
				{
					memoryStream.SeekFromBegin(0);
					List<GuiResourceError> errors;
					auto resource = GuiResource::LoadPrecompiledBinary(memoryStream, errors);
					CHECK_ERROR(errors.Count() == 0, L"PendingResource::LoadResource()#Failed to load the resource.");
					return resource;
				}
			};
			Group<WString, Ptr<PendingResource>>	depToPendings;
			SortedList<Ptr<PendingResource>>		pendingResources;

		public:

			GUI_PLUGIN_NAME(GacUI_Res_Resource)
			{
				GUI_PLUGIN_DEPEND(GacUI_Res_ResourceResolver);
			}

			void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerRelatedPlugins)
				{
					resourceManager = this;
					IGuiResourceResolverManager* manager = GetResourceResolverManager();
					manager->SetTypeResolver(Ptr(new GuiResourceClassNameRecordTypeResolver));
				}
			}

			void Unload(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerRelatedPlugins)
				{
					anonymousResources.Clear();
					resources.Clear();
					instanceResources.Clear();
					resourceManager = nullptr;
				}
			}

			void SetResource(Ptr<GuiResource> resource, GuiResourceError::List& errors, GuiResourceUsage usage)override
			{
				auto metadata = resource->GetMetadata();
				if (metadata->name == L"")
				{
					if (anonymousResources.Contains(resource.Obj())) return;
					resource->Initialize(usage, errors);
					if (errors.Count() > 0)
					{
						return;
					}
					anonymousResources.Add(resource);
				}
				else
				{
					CHECK_ERROR(!resources.Keys().Contains(metadata->name), L"GuiResourceManager::SetResource(Ptr<GuiResource>, GuiResourceUsage)#A resource with the same name has been loaded.");

					resource->Initialize(usage, errors);
					if (errors.Count() > 0)
					{
						return;
					}
					resources.Add(metadata->name, resource);
				}
				
				if (auto record = resource->GetValueByPath(L"Precompiled/ClassNameRecord").Cast<GuiResourceClassNameRecord>())
				{
					for (auto className : record->classNames)
					{
						instanceResources.Add(className, resource);
					}
				}

				if (metadata->name != L"")
				{
					vint index = depToPendings.Keys().IndexOf(metadata->name);
					if (index != -1)
					{
						List<Ptr<PendingResource>> prs;
						CopyFrom(prs, depToPendings.GetByIndex(index));
						depToPendings.Remove(metadata->name);

						for (auto pr : prs)
						{
							pr->dependencies.Remove(metadata->name);
							if (pr->dependencies.Count() == 0)
							{
								pendingResources.Remove(pr.Obj());
								SetResource(pr->LoadResource(), errors, pr->usage);
							}
						}
					}
				}
			}

			Ptr<GuiResource> GetResource(const WString& name)override
			{
				vint index = resources.Keys().IndexOf(name);
				if (index == -1) return nullptr;
				return resources.Values()[index];
			}

			Ptr<GuiResource> GetResourceFromClassName(const WString& classFullName)override
			{
				vint index = instanceResources.Keys().IndexOf(classFullName);
				if (index == -1) return nullptr;
				return instanceResources.Values()[index];
			}

			LazyList<Ptr<GuiResource>> GetLoadedResources()override
			{
				return From(anonymousResources).Concat(resources.Values());
			}

			bool UnloadResource(const WString& name)override
			{
				return UnloadResource(GetResource(name));
			}

			bool UnloadResource(Ptr<GuiResource> resource)override
			{
				if (!resource) return false;

				WString name;
				if (auto metadata = resource->GetMetadata())
				{
					name = metadata->name;
				}

				if (name == WString::Empty)
				{
					vint index = anonymousResources.IndexOf(resource.Obj());
					if (index == -1) return false;
					anonymousResources.RemoveAt(index);
				}
				else
				{
					vint index = resources.Keys().IndexOf(name);
					if (index == -1) return false;
					auto resource = resources.Values()[index];
					resources.Remove(name);
				}

				if (auto record = resource->GetValueByPath(L"Precompiled/ClassNameRecord").Cast<GuiResourceClassNameRecord>())
				{
					for (auto className : record->classNames)
					{
						instanceResources.Remove(className);
					}
				}
				return true;
			}

			void LoadResourceOrPending(stream::IStream& resourceStream, GuiResourceError::List& errors, GuiResourceUsage usage)override
			{
				auto pr = Ptr(new PendingResource);
				pr->usage = usage;
				CopyStream(resourceStream, pr->memoryStream);

				pr->metadata = Ptr(new GuiResourceMetadata);
				{
					pr->memoryStream.SeekFromBegin(0);
					stream::internal::ContextFreeReader reader(pr->memoryStream);
					WString metadata;
					reader << metadata;

					List<GuiResourceError> errors;
					auto parser = GetParserManager()->GetParser<XmlDocument>(L"XML");
					auto xmlMetadata = parser->Parse({}, metadata, errors);
					CHECK_ERROR(xmlMetadata, L"GuiResourceManager::LoadResourceOrPending(stream::IStream&, GuiResourceUsage)#This resource does not contain a valid metadata.");
					pr->metadata->LoadFromXml(xmlMetadata, {}, errors);
					CHECK_ERROR(errors.Count() == 0, L"GuiResourceManager::LoadResourceOrPending(stream::IStream&, GuiResourceUsage)#This resource does not contain a valid metadata.");
				}

				CHECK_ERROR(
					pr->metadata->name != L"" || pr->dependencies.Count() == 0,
					L"GuiResourceManager::LoadResourceOrPending(stream::IStream&, GuiResourceUsage)#The name of this resource cannot be empty because it has dependencies."
				);
				CopyFrom(pr->dependencies, From(pr->metadata->dependencies).Except(resources.Keys()));

				if (pr->dependencies.Count() == 0)
				{
					SetResource(pr->LoadResource(), errors, pr->usage);
				}
				else
				{
					pendingResources.Add(pr);
					for (auto dep : pr->dependencies)
					{
						depToPendings.Add(dep, pr);
					}
				}
			}

			void LoadResourceOrPending(stream::IStream& resourceStream, GuiResourceUsage usage)override
			{
				GuiResourceError::List errors;
				LoadResourceOrPending(resourceStream, errors, usage);
				CHECK_ERROR(errors.Count() == 0, L"GuiResourceManager::LoadResourceOrPending(stream::IStream&, GuiResourceUsage)#Error happened.");
			}

			void GetPendingResourceNames(collections::List<WString>& names)override
			{
				CopyFrom(names, From(pendingResources).Select([](Ptr<PendingResource> pr) {return pr->metadata->name; }));
			}
		};
		GUI_REGISTER_PLUGIN(GuiResourceManager)
	}
}


/***********************************************************************
.\RESOURCES\GUIRESOURCETYPERESOLVERS.CPP
***********************************************************************/

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

/***********************************************************************
Image Type Resolver (Image)
***********************************************************************/

		class GuiResourceImageTypeResolver
			: public Object
			, public IGuiResourceTypeResolver
			, private IGuiResourceTypeResolver_DirectLoadXml
			, private IGuiResourceTypeResolver_DirectLoadStream
		{
		public:
			WString GetType()override
			{
				return L"Image";
			}

			bool XmlSerializable()override
			{
				return true;
			}

			bool StreamSerializable()override
			{
				return true;
			}

			IGuiResourceTypeResolver_DirectLoadXml* DirectLoadXml()override
			{
				return this;
			}

			IGuiResourceTypeResolver_DirectLoadStream* DirectLoadStream()override
			{
				return this;
			}

			Ptr<glr::xml::XmlElement> Serialize(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content)override
			{
				return nullptr;
			}

			void SerializePrecompiled(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content, stream::IStream& binaryStream)override
			{
				auto obj = content.Cast<GuiImageData>();
				stream::internal::ContextFreeWriter writer(binaryStream);
				FileStream fileStream(resource->GetFileAbsolutePath(), FileStream::ReadOnly);
				writer << (stream::IStream&)fileStream;
			}

			Ptr<DescriptableObject> ResolveResource(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlElement> element, GuiResourceError::List& errors)override
			{
				errors.Add(GuiResourceError({ resource }, L"Image should load from file."));
				return nullptr;
			}

			Ptr<DescriptableObject> ResolveResource(Ptr<GuiResourceItem> resource, const WString& path, GuiResourceError::List& errors)override
			{
				Ptr<INativeImage> image = GetCurrentController()->ImageService()->CreateImageFromFile(path);
				if(image)
				{
					return Ptr(new GuiImageData(image, 0));
				}
				else
				{
					errors.Add(GuiResourceError({ resource }, L"Failed to load file \"" + path + L"\"."));
					return nullptr;
				}
			}

			Ptr<DescriptableObject> ResolveResourcePrecompiled(Ptr<GuiResourceItem> resource, stream::IStream& binaryStream, GuiResourceError::List& errors)override
			{
				stream::internal::ContextFreeReader reader(binaryStream);
				MemoryStream memoryStream;
				reader << (stream::IStream&)memoryStream;

				auto image = GetCurrentController()->ImageService()->CreateImageFromStream(memoryStream);
				if (image)
				{
					return Ptr(new GuiImageData(image, 0));
				}
				else
				{
					errors.Add(GuiResourceError({ resource }, L"[BINARY] Failed to load an image from binary data in a stream."));
					return nullptr;
				}
			}
		};

/***********************************************************************
Text Type Resolver (Text)
***********************************************************************/

		class GuiResourceTextTypeResolver
			: public Object
			, public IGuiResourceTypeResolver
			, private IGuiResourceTypeResolver_DirectLoadXml
			, private IGuiResourceTypeResolver_DirectLoadStream
		{
		public:
			WString GetType()override
			{
				return L"Text";
			}

			bool XmlSerializable()override
			{
				return true;
			}

			bool StreamSerializable()override
			{
				return true;
			}

			IGuiResourceTypeResolver_DirectLoadXml* DirectLoadXml()override
			{
				return this;
			}

			IGuiResourceTypeResolver_DirectLoadStream* DirectLoadStream()override
			{
				return this;
			}

			Ptr<glr::xml::XmlElement> Serialize(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content)override
			{
				if (auto obj = content.Cast<GuiTextData>())
				{
					auto xmlContent = Ptr(new XmlText);
					xmlContent->content.value = obj->GetText();

					auto xmlText = Ptr(new XmlElement);
					xmlText->name.value = L"Text";
					xmlText->subNodes.Add(xmlContent);

					return xmlText;
				}
				return 0;
			}

			void SerializePrecompiled(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content, stream::IStream& binaryStream)override
			{
				auto obj = content.Cast<GuiTextData>();
				stream::internal::ContextFreeWriter writer(binaryStream);
				WString text = obj->GetText();
				writer << text;
			}

			Ptr<DescriptableObject> ResolveResource(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlElement> element, GuiResourceError::List& errors)override
			{
				return Ptr(new GuiTextData(XmlGetValue(element)));
			}

			Ptr<DescriptableObject> ResolveResource(Ptr<GuiResourceItem> resource, const WString& path, GuiResourceError::List& errors)override
			{
				WString text;
				if(LoadTextFile(path, text))
				{
					return Ptr(new GuiTextData(text));
				}
				else
				{
					errors.Add(GuiResourceError({ resource }, L"Failed to load file \"" + path + L"\"."));
					return nullptr;
				}
			}

			Ptr<DescriptableObject> ResolveResourcePrecompiled(Ptr<GuiResourceItem> resource, stream::IStream& binaryStream, GuiResourceError::List& errors)override
			{
				stream::internal::ContextFreeReader reader(binaryStream);
				WString text;
				reader << text;
				return Ptr(new GuiTextData(text));
			}
		};

/***********************************************************************
Xml Type Resolver (Xml)
***********************************************************************/

		class GuiResourceXmlTypeResolver
			: public Object
			, public IGuiResourceTypeResolver
			, private IGuiResourceTypeResolver_DirectLoadXml
			, private IGuiResourceTypeResolver_DirectLoadStream
		{
		public:
			WString GetType()override
			{
				return L"Xml";
			}

			bool XmlSerializable()override
			{
				return true;
			}

			bool StreamSerializable()override
			{
				return true;
			}

			IGuiResourceTypeResolver_DirectLoadXml* DirectLoadXml()override
			{
				return this;
			}

			IGuiResourceTypeResolver_DirectLoadStream* DirectLoadStream()override
			{
				return this;
			}

			Ptr<glr::xml::XmlElement> Serialize(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content)override
			{
				if (auto obj = content.Cast<XmlDocument>())
				{
					auto xmlXml = Ptr(new XmlElement());
					xmlXml->name.value = L"Xml";
					xmlXml->subNodes.Add(obj->rootElement);
					return xmlXml;
				}
				return nullptr;
			}

			void SerializePrecompiled(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content, stream::IStream& binaryStream)override
			{
				auto obj = content.Cast<XmlDocument>();
				WString text = GenerateToStream([&](StreamWriter& writer)
				{
					XmlPrint(obj, writer);
				});
				stream::internal::ContextFreeWriter writer(binaryStream);
				writer << text;
			}

			Ptr<DescriptableObject> ResolveResource(Ptr<GuiResourceItem> resource, Ptr<glr::xml::XmlElement> element, GuiResourceError::List& errors)override
			{
				Ptr<XmlElement> root = XmlGetElements(element).First(0);
				if(root)
				{
					auto xml = Ptr(new XmlDocument);
					xml->rootElement=root;
					return xml;
				}
				return nullptr;
			}

			Ptr<DescriptableObject> ResolveResource(Ptr<GuiResourceItem> resource, const WString& path, GuiResourceError::List& errors)override
			{
				if (auto parser = GetParserManager()->GetParser<XmlDocument>(L"XML"))
				{
					WString text;
					if (LoadTextFile(path, text))
					{
						return parser->Parse({ resource }, text, errors);
					}
					else
					{
						errors.Add(GuiResourceError({ resource }, L"Failed to load file \"" + path + L"\"."));
					}
				}
				return nullptr;
			}

			Ptr<DescriptableObject> ResolveResourcePrecompiled(Ptr<GuiResourceItem> resource, stream::IStream& binaryStream, GuiResourceError::List& errors)override
			{
				if (auto parser = GetParserManager()->GetParser<XmlDocument>(L"XML"))
				{
					stream::internal::ContextFreeReader reader(binaryStream);
					WString text;
					reader << text;

					return parser->Parse({ resource }, text, errors);
				}
				return nullptr;
			}
		};

/***********************************************************************
Doc Type Resolver (Doc)
***********************************************************************/

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

			bool XmlSerializable()override
			{
				return true;
			}

			bool StreamSerializable()override
			{
				return true;
			}

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

			bool IsDelayLoad()override
			{
				return true;
			}

			IGuiResourceTypeResolver_IndirectLoad* IndirectLoad()override
			{
				return this;
			}

			Ptr<DescriptableObject> Serialize(Ptr<GuiResourceItem> resource, Ptr<DescriptableObject> content)override
			{
				if (auto obj = content.Cast<DocumentModel>())
				{
					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<DocumentModel> model = DocumentModel::LoadFromXml(resource, xml, resolver, errors);
					return model;
				}
				return nullptr;
			}
		};

/***********************************************************************
Type Resolver Plugin
***********************************************************************/

		class GuiResourceTypeResolversPlugin : public Object, public IGuiPlugin
		{
		public:

			GUI_PLUGIN_NAME(GacUI_Res_TypeResolvers)
			{
				GUI_PLUGIN_DEPEND(GacUI_Res_ResourceResolver);
			}

			void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
			{
				if (controllerUnrelatedPlugins)
				{
					IGuiResourceResolverManager* manager = GetResourceResolverManager();
					manager->SetTypeResolver(Ptr(new GuiResourceImageTypeResolver));
					manager->SetTypeResolver(Ptr(new GuiResourceTextTypeResolver));
					manager->SetTypeResolver(Ptr(new GuiResourceXmlTypeResolver));
					manager->SetTypeResolver(Ptr(new GuiResourceDocTypeResolver));
				}
			}

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


/***********************************************************************
.\UTILITIES\GUIUTILITIESREGISTRATION.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{

/***********************************************************************
Utilities Registration
***********************************************************************/

		FakeClipboardService* fakeClipboardService = nullptr;
		FakeDialogService* fakeDialogService = nullptr;

		void GuiInitializeUtilities()
		{
			GetNativeServiceSubstitution()->Substitute(INativeAutomationService::UnavailableService(), true);

			if (!fakeClipboardService)
			{
				fakeClipboardService = new FakeClipboardService;
				GetNativeServiceSubstitution()->Substitute(fakeClipboardService, true);
			}

			if (!fakeDialogService)
			{
				fakeDialogService = new FakeDialogService;
				GetNativeServiceSubstitution()->Substitute(fakeDialogService, true);
			}
		}

		void GuiFinalizeUtilities()
		{
			if (fakeClipboardService)
			{
				GetNativeServiceSubstitution()->Unsubstitute(fakeClipboardService);
				delete fakeClipboardService;
				fakeClipboardService = nullptr;
			}

			if (fakeDialogService)
			{
				GetNativeServiceSubstitution()->Unsubstitute(fakeDialogService);
				delete fakeDialogService;
				fakeDialogService = nullptr;
			}
		}
	}
}

/***********************************************************************
.\UTILITIES\FAKESERVICES\GUIFAKECLIPBOARDSERVICE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{

/***********************************************************************
FakeClipboardReader
***********************************************************************/

		class FakeClipboardReader : public Object, public INativeClipboardReader
		{
		public:
			Nullable<WString>			text;
			Ptr<DocumentModel>			document;
			Ptr<INativeImage>			image;

			bool ContainsText() override
			{
				return text;
			}

			WString GetText() override
			{
				return text ? text.Value() : WString();
			}

			bool ContainsDocument() override
			{
				return document;
			}

			Ptr<DocumentModel> GetDocument() override
			{
				return document;
			}

			bool ContainsImage() override
			{
				return image;
			}

			Ptr<INativeImage> GetImage() override
			{
				return image;
			}
		};

/***********************************************************************
FakeClipboardWriter
***********************************************************************/

		class FakeClipboardWriter : public Object, public INativeClipboardWriter
		{
		public:
			FakeClipboardService*		service;
			Ptr<FakeClipboardReader>	reader;

			FakeClipboardWriter(FakeClipboardService* _service)
				: service(_service)
			{
				reader = Ptr(new FakeClipboardReader);
			}

			void SetText(const WString& value) override
			{
				if (reader) reader->text = value;
			}

			void SetDocument(Ptr<DocumentModel> value) override
			{
				if (reader)
				{
					if (!reader->text) reader->text = value->GetTextForReading(WString::Unmanaged(L"\r\n\r\n"));;
					if (!reader->image) reader->image = GetImageFromSingleImageDocument(value);
					reader->document = value;
					ModifyDocumentForClipboard(reader->document);
				}
			}

			void SetImage(Ptr<INativeImage> value) override
			{
				if (reader) reader->image = value;
			}

			bool Submit() override
			{
				if (!reader) return false;
				service->reader = reader;
				reader = nullptr;
				service = nullptr;
				GetCurrentController()->CallbackService()->Invoker()->InvokeClipboardUpdated();
				return true;
			}
		};

/***********************************************************************
FakeClipboardService
***********************************************************************/

		FakeClipboardService::FakeClipboardService()
			: reader(Ptr(new FakeClipboardReader))
		{
		}

		FakeClipboardService::~FakeClipboardService()
		{
		}

		Ptr<INativeClipboardReader> FakeClipboardService::ReadClipboard()
		{
			return reader;
		}

		Ptr<INativeClipboardWriter> FakeClipboardService::WriteClipboard()
		{
			return Ptr(new FakeClipboardWriter(this));
		}
	}
}

/***********************************************************************
.\UTILITIES\FAKESERVICES\GUIFAKEDIALOGSERVICEBASE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace compositions;
		using namespace controls;

/***********************************************************************
FakeDialogServiceBase
***********************************************************************/

		void FakeDialogServiceBase::ShowModalDialogAndDelete(Ptr<IDescriptable> viewModel, controls::GuiWindow* owner, controls::GuiWindow* dialog)
		{
			auto app = GetApplication();
			bool exit = false;

			dialog->WindowOpened.AttachLambda([=](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
			{
				dialog->ForceCalculateSizeImmediately();
				dialog->MoveToScreenCenter();
			});

			auto movingFlag = Ptr(new bool(false));
			dialog->ControlSignalTrigerred.AttachLambda([=](GuiGraphicsComposition* sender, GuiControlSignalEventArgs& arguments)
			{
				if (arguments.controlSignal == ControlSignal::UpdateFullfilled)
				{
					if (!*movingFlag.Obj())
					{
						*movingFlag.Obj() = true;
						dialog->MoveToScreenCenter();
					}
				}
			});

			dialog->ShowModalAndDelete(owner, [&exit]() { exit = true; }, [viewModel]() { (void)viewModel; });
			while (!exit && app->RunOneCycle());
		}

		FakeDialogServiceBase::FakeDialogServiceBase()
		{
		}

		FakeDialogServiceBase::~FakeDialogServiceBase()
		{
		}
	}
}

/***********************************************************************
.\UTILITIES\FAKESERVICES\GUIFAKEDIALOGSERVICEBASE_COLORDIALOG.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace controls;

/***********************************************************************
View Model (IColorDialogViewModel)
***********************************************************************/

		class FakeColorDialogViewModel : public Object, public virtual IColorDialogViewModel
		{
		public:
			bool					confirmed = false;
			Color					color;

			bool					GetConfirmed() override					{ return confirmed; }
			void					SetConfirmed(bool value) override		{ confirmed = value; }

			Color					GetColor() override						{ return color; }
			void					SetColor(Color value) override			{ color = value; }
		};

/***********************************************************************
FakeDialogServiceBase
***********************************************************************/

		bool FakeDialogServiceBase::ShowColorDialog(
			INativeWindow* window,
			Color& selection,
			bool selected,
			ColorDialogCustomColorOptions customColorOptions,
			Color* customColors
		)
		{
			auto vm = Ptr(new FakeColorDialogViewModel);
			vm->color = selection;
			{
				auto owner = GetApplication()->GetWindowFromNative(window);
				auto dialog = CreateColorDialog(vm);
				ShowModalDialogAndDelete(vm, owner, dialog);
			}
			if (vm->confirmed)
			{
				selection = vm->color;
			}
			return vm->confirmed;
		}
	}
}

/***********************************************************************
.\UTILITIES\FAKESERVICES\GUIFAKEDIALOGSERVICEBASE_FILEDIALOG.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace regex;
		using namespace controls;

/***********************************************************************
View Model (IFileDialogFilter)
***********************************************************************/

		class FileDialogFilter : public Object, public virtual IFileDialogFilter
		{
		public:
			WString						name;
			WString						filter;
			Nullable<WString>			defaultExtension;
			Ptr<Regex>					regexFilter;

			WString GetName() override
			{
				return name;
			}

			WString GetFilter() override
			{
				return filter;
			}

			Nullable<WString> GetDefaultExtension() override
			{
				return defaultExtension;
			}

			bool FilterFile(Ptr<IFileDialogFile> file) override
			{
				if (file->GetType() != FileDialogFileType::File) return true;
				auto name = file->GetName();
				auto match = regexFilter->MatchHead(name);
				return match && match->Result().Length() == name.Length();
			}
		};

/***********************************************************************
View Model (IFileDialogFolder)
***********************************************************************/

		class FileDialogFolder : public Object, public virtual IFileDialogFolder
		{
			using FolderMap = Dictionary<WString, Ptr<FileDialogFolder>>;
		protected:
			vint						taskId = 0;
			bool						taskFired = false;

		public:
			FileDialogFolder*			parent = nullptr;
			FileDialogFolderType		type = FileDialogFolderType::Placeholder;
			filesystem::Folder			folder;
			WString						name;
			vint						index = -1;
			WString						textLoadingFolders;

			// the placeholder node will always be the last one
			Folders						children;
			FolderMap					childrenByName;

			void AddChild(Ptr<FileDialogFolder> child)
			{
				child->textLoadingFolders = textLoadingFolders;
				child->parent = this;
				if (child->type == FileDialogFolderType::Folder)
				{
					childrenByName.Add(child->name, child);
				}
				child->index = HasPlaceholderChild() ? children.Count() - 1 : children.Count();
				children.Insert(child->index, child);
			}

			bool HasPlaceholderChild()
			{
				return children.Count() > 0 && children[children.Count() - 1]->GetType() == FileDialogFolderType::Placeholder;
			}

			void AddPlaceholderChild()
			{
				if (HasPlaceholderChild()) return;
				CHECK_ERROR(textLoadingFolders.Length() > 0, L"vl::presentation::FileDialogFolder::AddPlaceholderChild()#textLoadingFolders is not initialized.");
				auto child = Ptr(new FileDialogFolder);
				child->name = textLoadingFolders;
				AddChild(child);
			}

			void RemovePlaceholderChild()
			{
				if (HasPlaceholderChild())
				{
					children.RemoveAt(children.Count() - 1);
				}
			}

			FileDialogFolder() = default;

			FileDialogFolder(const filesystem::Folder& _folder)
				: type(FileDialogFolderType::Folder)
				, folder(_folder)
				, name(_folder.GetFilePath().GetName())
			{
			}

			Ptr<IFileDialogFolder> GetParent() override
			{
				return Ptr(static_cast<IFileDialogFolder*>(parent));
			}

			FileDialogFolderType GetType() override
			{
				if (type == FileDialogFolderType::Placeholder && !taskFired)
				{
					taskFired = true;
					auto taskFolder = Ptr(parent);
					vint taskFolderId = ++taskFolder->taskId;
					GetApplication()->InvokeAsync([taskFolder, taskFolderId]()
					{
						auto subFolders = Ptr(new List<filesystem::Folder>);
						if (!taskFolder->folder.GetFolders(*subFolders.Obj()))
						{
							subFolders->Clear();
						}

						GetApplication()->InvokeInMainThread(nullptr, [taskFolder, taskFolderId, subFolders]()
						{
							if (taskFolder->taskId == taskFolderId)
							{
								taskFolder->RemovePlaceholderChild();
								for (auto subFolder : *subFolders.Obj())
								{
									if (!taskFolder->childrenByName.Keys().Contains(subFolder.GetFilePath().GetName()))
									{
										auto child = Ptr(new FileDialogFolder(subFolder));
										taskFolder->AddChild(child);
										child->AddPlaceholderChild();
									}
								}
							}
						});
					});
				}
				return type;
			}

			WString GetFullPath() override
			{
				return folder.GetFilePath().GetFullPath();
			}

			WString GetName() override
			{
				return name;
			}

			vint GetIndex() override
			{
				return index;
			}

			Folders& GetFolders() override
			{
				return children;
			}

			Ptr<IFileDialogFolder> TryGetFolder(const WString& name) override
			{
				vint index = childrenByName.Keys().IndexOf(name);
				if (index == -1) return {};
				return childrenByName.Values()[index];
			}
		};

/***********************************************************************
View Model (IFileDialogFile)
***********************************************************************/

		class FileDialogFile : public Object, public virtual IFileDialogFile
		{
		public:
			FileDialogFileType			type = FileDialogFileType::Placeholder;
			Ptr<FileDialogFolder>		associatedFolder;
			WString						name;

			FileDialogFileType GetType() override
			{
				return type;
			}

			Ptr<IFileDialogFolder> GetAssociatedFolder() override
			{
				return associatedFolder;
			}

			WString GetName() override
			{
				return name;
			}
		};

/***********************************************************************
View Model (IFileDialogViewModel)
***********************************************************************/

		class FileDialogViewModel : public Object, public virtual IFileDialogViewModel
		{
			using ConfirmedSelection = collections::List<WString>;
		protected:
			WString						textLoadingFolders;
			WString						textLoadingFiles;
			WString						dialogErrorEmptySelection;
			WString						dialogErrorFileNotExist;
			WString						dialogErrorFileExpected;
			WString						dialogErrorFolderNotExist;
			WString						dialogErrorMultipleSelectionNotEnabled;
			WString						dialogAskCreateFile;
			WString						dialogAskOverrideFile;

			bool						isLoadingFiles = false;
			filesystem::FilePath		loadingPath;
			vint						loadingTaskId = 0;
			Files						files;
			Regex						regexDisplayString{ L";" };

		public:
			FakeDialogServiceBase*      dialogService = nullptr;

			bool						selectToSave = false;
			bool						confirmed = false;
			ConfirmedSelection			confirmedSelection;

			WString						title;
			bool						enabledMultipleSelection = false;
			bool						fileMustExist = false;
			bool						folderMustExist = false;
			bool						promptCreateFile = false;
			bool						promptOverriteFile = false;
			WString						defaultExtension;

			Filters						filters;
			Ptr<FileDialogFilter>		selectedFilter;

			WString						initialDirectory;
			Ptr<FileDialogFolder>		rootFolder;
			Ptr<FileDialogFolder>		selectedFolder;

			WString GetTitle() override
			{
				return title;
			}

			bool GetEnabledMultipleSelection() override
			{
				return enabledMultipleSelection;
			}

			WString GetDefaultExtension() override
			{
				return defaultExtension;
			}

			const Filters& GetFilters() override
			{
				return filters;
			}

			Ptr<IFileDialogFilter> GetSelectedFilter() override
			{
				return selectedFilter;
			}

			void SetSelectedFilter(Ptr<IFileDialogFilter> value) override
			{
				if (auto filter = value.Cast<FileDialogFilter>())
				{
					if (selectedFilter != filter && filters.Contains(value.Obj()))
					{
						selectedFilter = filter;
						SelectedFilterChanged();
					}
				}
			}

			Ptr<IFileDialogFolder> GetRootFolder() override
			{
				return rootFolder;
			}

			Ptr<IFileDialogFolder> GetSelectedFolder() override
			{
				return selectedFolder;
			}

			void SetSelectedFolderInternal(Ptr<IFileDialogFolder> value, bool refreshFile)
			{
				if (auto folder = value.Cast<FileDialogFolder>())
				{
					if (selectedFolder != folder)
					{
						selectedFolder = folder;
						SelectedFolderChanged();

						if (refreshFile && loadingPath != selectedFolder->folder.GetFilePath())
						{
							RefreshFiles();
						}
					}
				}
			}

			void SetSelectedFolderInternal(filesystem::FilePath path, bool refreshFile)
			{
				List<filesystem::FilePath> fragments;
				while (!path.IsRoot())
				{
					fragments.Add(path);
					path = path.GetFolder();
				}

				auto folder = rootFolder;
				// TODO: (enumerable) foreach:reversed
				for (vint i = fragments.Count() - 1; i >= 0; i--)
				{
					auto fragment = fragments[i];
					vint index = folder->childrenByName.Keys().IndexOf(fragment.GetName());
					if (index == -1)
					{
						auto child = Ptr(new FileDialogFolder(fragment));
						folder->AddChild(child);
						child->AddPlaceholderChild();
						folder = child;
					}
					else
					{
						folder = folder->childrenByName.Values()[index];
					}
				}

				SetSelectedFolderInternal(folder, refreshFile);
			}

			void SetSelectedFolder(Ptr<IFileDialogFolder> value) override
			{
				SetSelectedFolderInternal(value, true);
			}

			bool GetIsLoadingFiles() override
			{
				return isLoadingFiles;
			}

			Files& GetFiles() override
			{
				return files;
			}

			void RefreshFiles() override
			{
				if (!selectedFolder) return;

				vint taskId = ++loadingTaskId;
				auto taskFolder = selectedFolder;
				auto taskPath = (loadingPath = selectedFolder->folder.GetFilePath());
				if (!isLoadingFiles)
				{
					isLoadingFiles = true;
					IsLoadingFilesChanged();

					files.Clear();
					{
						auto item = Ptr(new FileDialogFile);
						item->name = textLoadingFiles;
						files.Add(item);
					}
				}

				auto vm = Ptr(this);
				GetApplication()->InvokeAsync([taskId, taskFolder, taskPath, vm]()
				{
					auto folders = Ptr(new List<filesystem::Folder>);
					auto files = Ptr(new List<filesystem::File>);
					filesystem::Folder loadingFolder = taskPath;
					if (!loadingFolder.GetFolders(*folders.Obj()) || !loadingFolder.GetFiles(*files.Obj()))
					{
						folders->Clear();
						files->Clear();
					}

					GetApplication()->InvokeInMainThread(nullptr, [taskId, taskFolder, folders, files, vm]()
					{
						if (vm->loadingTaskId == taskId)
						{
							vm->files.Clear();

							for (auto folder : *folders.Obj())
							{
								auto item = Ptr(new FileDialogFile);
								item->type = FileDialogFileType::Folder;
								item->name = folder.GetFilePath().GetName();

								vint index = taskFolder->childrenByName.Keys().IndexOf(item->name);
								if (index == -1)
								{
									auto associatedFolder = Ptr(new FileDialogFolder(folder));
									taskFolder->AddChild(associatedFolder);
									associatedFolder->AddPlaceholderChild();
									item->associatedFolder = associatedFolder;
								}
								else
								{
									item->associatedFolder = taskFolder->childrenByName.Values()[index];
								}

								vm->files.Add(item);
							}

							for (auto file : *files.Obj())
							{
								auto item = Ptr(new FileDialogFile);
								item->type = FileDialogFileType::File;
								item->name = file.GetFilePath().GetName();
								vm->files.Add(item);
							}

							vm->isLoadingFiles = false;
							vm->IsLoadingFilesChanged();
						}
					});
				});
			}

			WString GetDisplayString(collections::LazyList<Ptr<IFileDialogFile>> files) override
			{
				return From(files)
					.FindType<FileDialogFile>()
					.Where([](auto file) { return file->type != FileDialogFileType::Placeholder; })
					.Select([](auto file) { return WString::Unmanaged(L"\"") + file->name + WString::Unmanaged(L"\""); })
					.Aggregate(WString::Empty, [](auto&& a, auto&& b)
					{
						return a == WString::Empty ? b : a + WString::Unmanaged(L";") + b;
					});
			}

			Selection ParseDisplayString(const WString& displayString) override
			{
				auto items = Ptr(new RegexMatch::List);
				regexDisplayString.Split(displayString, false, *items.Obj());
				return From(LazyList<Ptr<RegexMatch>>(items))
					.Select([](auto item) { return item->Result().Value(); })
					.Select([](auto item)
					{
						if (item.Length() >= 2 && item[0] == L'\"' && item[item.Length() - 1] == L'\"')
						{
							return item.Sub(1, item.Length() - 2);
						}
						else
						{
							return item;
						}
					});
			}

			bool TryConfirm(controls::GuiWindow* owner, Selection selectedPaths) override
			{
				CHECK_ERROR(dialogService, L"vl::presentation::FileDialogViewModel::TryConfirm()#dialogService is not initialized.");
				auto wd = selectedFolder->folder.GetFilePath();
				List<filesystem::FilePath> rawPaths;
				CopyFrom(
					rawPaths,
					selectedPaths.Select([this, wd](auto path) { return wd / path; })
					);

				if (rawPaths.Count() == 0)
				{
					dialogService->ShowMessageBox(
						owner ? owner->GetNativeWindow() : nullptr,
						dialogErrorEmptySelection,
						owner->GetText(),
						INativeDialogService::DisplayOK,
						INativeDialogService::DefaultFirst,
						INativeDialogService::IconError,
						INativeDialogService::ModalWindow
						);
					return false;
				}

				// folder navigation must use the raw selection (no extension append)
				if (rawPaths.Count() == 1)
				{
					auto path = rawPaths[0];
					if (filesystem::Folder(path).Exists())
					{
						SetSelectedFolderInternal(path, true);
						return false;
					}
				}
				else if (!enabledMultipleSelection)
				{
					dialogService->ShowMessageBox(
						owner ? owner->GetNativeWindow() : nullptr,
						dialogErrorMultipleSelectionNotEnabled,
						owner->GetText(),
						INativeDialogService::DisplayOK,
						INativeDialogService::DefaultFirst,
						INativeDialogService::IconError,
						INativeDialogService::ModalWindow
						);
					return false;
				}

				Nullable<WString> extension;
				bool extensionFromFilter = false;
				if (selectedFilter)
				{
					extension = selectedFilter->GetDefaultExtension();
					extensionFromFilter = extension;
				}

				if (!extensionFromFilter && defaultExtension != WString::Empty)
				{
					// Only use the dialog default extension if it matches the current filter
					if (selectedFilter && selectedFilter->regexFilter)
					{
						auto testName = WString::Unmanaged(L"x.") + defaultExtension;
						auto match = selectedFilter->regexFilter->MatchHead(testName);
						if (match && match->Result().Length() == testName.Length())
						{
							extension = defaultExtension;
						}
					}
					else
					{
						extension = defaultExtension;
					}
				}

				auto normalized = [&](filesystem::FilePath path)
				{
					if (!extension) return path;

					auto&& sExt = WString::Unmanaged(L".") + extension.Value();
					vint lExt = sExt.Length();
					auto full = path.GetFullPath();

					auto selectedFileName = path.GetName();
					if (selectedFilter && selectedFilter->regexFilter)
					{
						auto match = selectedFilter->regexFilter->MatchHead(selectedFileName);
						if (match && match->Result().Length() == selectedFileName.Length())
						{
							return path;
						}
					}
					if (INVLOC.FindFirst(selectedFileName, WString::Unmanaged(L"."), Locale::None).key != -1)
					{
						return path;
					}
					return filesystem::FilePath(full + sExt);
				};

				List<filesystem::FilePath> paths;
				CopyFrom(paths, From(rawPaths).Select([&](auto path) { return normalized(path); }));

				List<vint> files, folders, unexistings;
				for (auto [path, index] : indexed(paths))
				{
					if (filesystem::File(path).Exists())
					{
						files.Add(index);
					}
					else if (filesystem::Folder(path).Exists())
					{
						folders.Add(index);
					}
					else
					{
						unexistings.Add(index);
					}
				}

				if (folders.Count() > 0)
				{
					auto message = stream::GenerateToStream([&](stream::TextWriter& writer)
					{
						writer.WriteString(dialogErrorFileExpected);
						for (vint index : folders)
						{
							writer.WriteLine(WString::Empty);
							writer.WriteString(L"  ");
							writer.WriteString(wd.GetRelativePathFor(paths[index]));
						}
					});
					dialogService->ShowMessageBox(
						owner ? owner->GetNativeWindow() : nullptr,
						message,
						owner->GetText(),
						INativeDialogService::DisplayOK,
						INativeDialogService::DefaultFirst,
						INativeDialogService::IconError,
						INativeDialogService::ModalWindow
						);
					return false;
				}

				if (unexistings.Count() > 0)
				{
					if (fileMustExist)
					{
						auto message = stream::GenerateToStream([&](stream::TextWriter& writer)
						{
							writer.WriteString(dialogErrorFileNotExist);
							for (vint index : unexistings)
							{
								writer.WriteLine(WString::Empty);
								writer.WriteString(L"  ");
								writer.WriteString(wd.GetRelativePathFor(paths[index]));
							}
						});
						dialogService->ShowMessageBox(
							owner ? owner->GetNativeWindow() : nullptr,
							message,
							owner->GetText(),
							INativeDialogService::DisplayOK,
							INativeDialogService::DefaultFirst,
							INativeDialogService::IconError,
							INativeDialogService::ModalWindow
							);
						return false;
					}

					if (folderMustExist)
					{
						SortedList<filesystem::FilePath> folderOfUnexistings;
						for (vint index : unexistings)
						{
							auto path = paths[index].GetFolder();
							if(!folderOfUnexistings.Contains(path))
							{
								folderOfUnexistings.Add(path);
							}
						}

						// TODO: (enumerable) foreach:indexed(alterable(reversed))
						for (vint i = folderOfUnexistings.Count() - 1; i >= 0; i--)
						{
							if (filesystem::Folder(folderOfUnexistings[i]).Exists())
							{
								folderOfUnexistings.RemoveAt(i);
							}
						}

						if (folderOfUnexistings.Count() > 0)
						{
							auto message = stream::GenerateToStream([&](stream::TextWriter& writer)
							{
								writer.WriteString(dialogErrorFolderNotExist);
								for (auto path : folderOfUnexistings)
								{
									writer.WriteLine(WString::Empty);
									writer.WriteString(L"  ");
									writer.WriteString(wd.GetRelativePathFor(path));
								}
							});
							dialogService->ShowMessageBox(
								owner ? owner->GetNativeWindow() : nullptr,
								message,
								owner->GetText(),
								INativeDialogService::DisplayOK,
								INativeDialogService::DefaultFirst,
								INativeDialogService::IconError,
								INativeDialogService::ModalWindow
								);
							return false;
						}
					}
				}

				WString questionMessage;
				List<vint>* questionFiles = nullptr;
				if (selectToSave && promptOverriteFile)
				{
					questionMessage = dialogAskOverrideFile;
					questionFiles = &files;
				}
				if (!selectToSave && promptCreateFile && unexistings.Count() > 0)
				{
					questionMessage = dialogAskCreateFile;
					questionFiles = &unexistings;
				}

				if (questionFiles && questionFiles->Count() > 0)
				{
					auto message = stream::GenerateToStream([&](stream::TextWriter& writer)
					{
						writer.WriteString(questionMessage);
						for (vint index : *questionFiles)
						{
							writer.WriteLine(WString::Empty);
							writer.WriteString(L"  ");
							writer.WriteString(wd.GetRelativePathFor(paths[index]));
						}
					});

					auto result = dialogService->ShowMessageBox(
						owner ? owner->GetNativeWindow() : nullptr,
						message,
						owner->GetText(),
						INativeDialogService::DisplayOKCancel,
						INativeDialogService::DefaultThird,
						INativeDialogService::IconQuestion,
						INativeDialogService::ModalWindow
						);

					if (result == INativeDialogService::SelectCancel)
					{
						return false;
					}
				}

				CopyFrom(
					confirmedSelection,
					From(paths).Select([](auto path) { return path.GetFullPath(); })
					);

				confirmed = true;
				return true;
			}

			void InitLocalizedText(
				const WString& _textLoadingFolders,
				const WString& _textLoadingFiles,
				const WString& _dialogErrorEmptySelection,
				const WString& _dialogErrorFileNotExist,
				const WString& _dialogErrorFileExpected,
				const WString& _dialogErrorFolderNotExist,
				const WString& _dialogErrorMultipleSelectionNotEnabled,
				const WString& _dialogAskCreateFile,
				const WString& _dialogAskOverrideFile
			) override
			{
				textLoadingFolders = _textLoadingFolders;
				textLoadingFiles = _textLoadingFiles;
				dialogErrorEmptySelection = _dialogErrorEmptySelection;
				dialogErrorFileNotExist = _dialogErrorFileNotExist;
				dialogErrorFileExpected = _dialogErrorFileExpected;
				dialogErrorFolderNotExist = _dialogErrorFolderNotExist;
				dialogErrorMultipleSelectionNotEnabled = _dialogErrorMultipleSelectionNotEnabled;
				dialogAskCreateFile = _dialogAskCreateFile;
				dialogAskOverrideFile = _dialogAskOverrideFile;

				rootFolder->textLoadingFolders = textLoadingFolders;
				rootFolder->AddPlaceholderChild();

				if (initialDirectory != WString::Empty)
				{
					filesystem::FilePath path = initialDirectory;
					if (filesystem::Folder(path).Exists())
					{
						SetSelectedFolderInternal(path, false);
						return;
					}
				}
				SetSelectedFolderInternal(rootFolder, false);
			}
		};

/***********************************************************************
FakeDialogServiceBase
***********************************************************************/

		void FakeDialogServiceBase::ParseFileDialogFilter(const WString& filter, collections::List<FilterDesc>& descs)
		{
			auto GetSingleWildcardDefaultExtension = [](const WString& wildcard) -> Nullable<WString>
			{
				// Accept only "*.<ext>" where <ext> is non-empty and contains no '*', '?', or ';'.
				if (wildcard.Length() < 3) return {};
				if (wildcard[0] != L'*' || wildcard[1] != L'.') return {};
				auto ext = wildcard.Right(wildcard.Length() - 2);
				for (vint i = 0; i < ext.Length(); i++)
				{
					switch (ext[i])
					{
					case L'*':
					case L'?':
					case L';':
						return {};
					}
				}
				return Nullable<WString>(ext);
			};

			auto GetFilterDefaultExtension = [&](const WString& wildcardExpr) -> Nullable<WString>
			{
				// Split by ';' and return the first qualifying extension
				vint start = 0;
				while (start <= wildcardExpr.Length())
				{
					vint semicolonPos = -1;
					for (vint i = start; i < wildcardExpr.Length(); i++)
					{
						if (wildcardExpr[i] == L';')
						{
							semicolonPos = i;
							break;
						}
					}
					auto part = (semicolonPos == -1)
						? wildcardExpr.Right(wildcardExpr.Length() - start)
						: wildcardExpr.Sub(start, semicolonPos - start);
					auto ext = GetSingleWildcardDefaultExtension(part);
					if (ext) return ext;
					if (semicolonPos == -1) break;
					start = semicolonPos + 1;
				}
				return {};
			};

			Regex regexWildcard(L"[*?;]");
			vint filterStart = 0;
			while (true)
			{
				vint first = -1;
				vint second = -1;
				vint count = filter.Length();

				for (vint i = filterStart; i < count; i++)
				{
					if (filter[i] == L'|')
					{
						first = i;
						break;
					}
				}
				if (first == -1) break;

				for (vint i = first + 1; i < count; i++)
				{
					if (filter[i] == L'|')
					{
						second = i;
						break;
					}
				}

				FilterDesc desc;
				desc.name = filter.Sub(filterStart, first - filterStart);
				desc.filter = filter.Sub(first + 1, (second == -1 ? count : second) - first - 1);
				desc.defaultExtensionOverride = GetFilterDefaultExtension(desc.filter);
				desc.regexFilterCode = stream::GenerateToStream([&](stream::TextWriter& writer)
				{
					writer.WriteString(L"^(");
					List<Ptr<RegexMatch>> matches;
					regexWildcard.Cut(desc.filter, false, matches);
					for (auto match : matches)
					{
						if (match->Success())
						{
							auto wildcard = match->Result().Value()[0];
							switch (wildcard)
							{
							case L'*':
								writer.WriteString(WString::Unmanaged(L"/.*"));
								break;
							case L'?':
								writer.WriteString(WString::Unmanaged(L"/."));
								break;
							case L';':
								writer.WriteString(WString::Unmanaged(L"|"));
								break;
							}
						}
						else
						{
							writer.WriteString(u32tow(regex_internal::EscapeTextForRegex(wtou32(match->Result().Value()))));
						}
					}
					writer.WriteString(L")$");
				});
				desc.regexFilter = Ptr(new Regex(desc.regexFilterCode));
				descs.Add(std::move(desc));

				if (second == -1) break;
				filterStart = second + 1;
			}
		}

		bool FakeDialogServiceBase::ShowFileDialog(
			INativeWindow* window,
			collections::List<WString>& selectionFileNames,
			vint& selectionFilterIndex,
			FileDialogTypes dialogType,
			const WString& title,
			const WString& initialFileName,
			const WString& initialDirectory,
			const WString& defaultExtension,
			const WString& filter,
			FileDialogOptions options
		)
		{
			auto vm = Ptr(new FileDialogViewModel);
			vm->dialogService = this;
			vm->title = title;
			vm->enabledMultipleSelection = (options & INativeDialogService::FileDialogAllowMultipleSelection) != 0;
			vm->fileMustExist = (options & INativeDialogService::FileDialogFileMustExist) != 0;
			vm->folderMustExist = (options & INativeDialogService::FileDialogDirectoryMustExist) != 0;
			vm->promptCreateFile = (options & INativeDialogService::FileDialogPromptCreateFile) != 0;
			vm->promptOverriteFile = (options & INativeDialogService::FileDialogPromptOverwriteFile) != 0;
			vm->defaultExtension = defaultExtension;

			List<FilterDesc> filterDescs;
			ParseFileDialogFilter(filter, filterDescs);
			for (auto&& desc : filterDescs)
			{
				auto filterItem = Ptr(new FileDialogFilter);
				filterItem->name = desc.name;
				filterItem->filter = desc.filter;
				filterItem->defaultExtension = desc.defaultExtensionOverride;
				filterItem->regexFilter = desc.regexFilter;
				vm->filters.Add(filterItem);
			}

			if (vm->filters.Count() > 0)
			{
				if (selectionFilterIndex < 0 || vm->filters.Count() <= selectionFilterIndex)
				{
					selectionFilterIndex = 0;
				}
				vm->selectedFilter = vm->filters[selectionFilterIndex].Cast<FileDialogFilter>();
			}

			vm->initialDirectory = initialDirectory;
			vm->rootFolder = Ptr(new FileDialogFolder);
			vm->rootFolder->type = FileDialogFolderType::Root;

			switch (dialogType)
			{
			case INativeDialogService::FileDialogOpen:
			case INativeDialogService::FileDialogOpenPreview:
				{
					vm->selectToSave = false;
					auto owner = GetApplication()->GetWindowFromNative(window);
					auto dialog = CreateOpenFileDialog(vm);
					ShowModalDialogAndDelete(vm, owner, dialog);
				}
				break;
			case INativeDialogService::FileDialogSave:
			case INativeDialogService::FileDialogSavePreview:
				{
					vm->selectToSave = true;
					auto owner = GetApplication()->GetWindowFromNative(window);
					auto dialog = CreateSaveFileDialog(vm);
					ShowModalDialogAndDelete(vm, owner, dialog);
				}
				break;
			}

			if (vm->filters.Count() > 0)
			{
				selectionFilterIndex = vm->filters.IndexOf(vm->selectedFilter.Obj());
			}

			if (vm->confirmed)
			{
				CopyFrom(selectionFileNames, vm->confirmedSelection);
			}
			return vm->confirmed;
		}
	}
}


/***********************************************************************
.\UTILITIES\FAKESERVICES\GUIFAKEDIALOGSERVICEBASE_FONTDIALOG.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace controls;

/***********************************************************************
View Model (ICommonFontDialogViewModel)
***********************************************************************/

		template<typename IViewModel>
		class FakeFontDialogViewModel : public Object, public virtual IViewModel
		{
		public:
			using FontList = collections::List<WString>;

			bool					confirmed = false;
			bool					fontMustExist = false;
			FontList				fontList;

			bool					GetConfirmed() override					{ return confirmed; }
			void					SetConfirmed(bool value) override		{ confirmed = value; }

			bool					GetFontMustExist() override				{ return fontMustExist; }
			const FontList&			GetFontList() override					{ return fontList; }
		};

/***********************************************************************
View Model (ISimpleFontDialogViewModel)
***********************************************************************/

		class FakeSimpleFontDialogViewModel : public FakeFontDialogViewModel<ISimpleFontDialogViewModel>
		{
		public:
			WString					fontFamily;
			vint					fontSize = 0;

			WString					GetFontFamily() override						{ return fontFamily; }
			void					SetFontFamily(const WString& value) override	{ fontFamily = value; }

			vint					GetFontSize() override							{ return fontSize; }
			void					SetFontSize(vint value) override				{ fontSize = value; }
		};

/***********************************************************************
View Model (IFullFontDialogViewModel)
***********************************************************************/

		class FakeFullFontDialogViewModel : public FakeFontDialogViewModel<IFullFontDialogViewModel>
		{
		public:
			Color					color;
			FontProperties			font;

			Color					GetColor() override								{ return color; }
			void					SetColor(Color value) override					{ color = value; }

			FontProperties			GetFont() override								{ return font; }
			void					SetFont(const FontProperties& value) override	{ font = value; }

			bool SelectColor(controls::GuiWindow* owner) override
			{
				return GetCurrentController()->DialogService()->ShowColorDialog(
					owner->GetNativeWindow(),
					color
					);
			}
		};

/***********************************************************************
FakeDialogServiceBase
***********************************************************************/

		bool FakeDialogServiceBase::ShowFontDialog(
			INativeWindow* window,
			FontProperties& selectionFont,
			Color& selectionColor,
			bool selected,
			bool showEffect,
			bool forceFontExist
		)
		{
			auto initVm = [=](auto vm)
			{
				vm->fontMustExist = forceFontExist;
				GetCurrentController()->ResourceService()->EnumerateFonts(vm->fontList);
				if (vm->fontList.Count() > 0)
				{
					Sort(&vm->fontList[0], vm->fontList.Count());
				}
			};

			if (showEffect)
			{
				auto vm = Ptr(new FakeFullFontDialogViewModel);
				initVm(vm);

				vm->font = selectionFont;
				vm->color = selectionColor;
				{
					auto owner = GetApplication()->GetWindowFromNative(window);
					auto dialog = CreateFullFontDialog(vm);
					ShowModalDialogAndDelete(vm, owner, dialog);
				}
				if (vm->confirmed)
				{
					selectionFont = vm->font;
					selectionColor = vm->color;
				}
				return vm->confirmed;
			}
			else
			{
				auto vm = Ptr(new FakeSimpleFontDialogViewModel);
				initVm(vm);

				vm->fontFamily = selectionFont.fontFamily;
				vm->fontSize = selectionFont.size;
				{
					auto owner = GetApplication()->GetWindowFromNative(window);
					auto dialog = CreateSimpleFontDialog(vm);
					ShowModalDialogAndDelete(vm, owner, dialog);
				}
				if (vm->confirmed)
				{
					selectionFont.fontFamily = vm->fontFamily;
					selectionFont.size = vm->fontSize;
				}
				return vm->confirmed;
			}
		}
	}
}

/***********************************************************************
.\UTILITIES\FAKESERVICES\GUIFAKEDIALOGSERVICEBASE_MESSAGEBOX.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace controls;

/***********************************************************************
View Model (IMessageBoxDialogViewModel)
***********************************************************************/

		class FakeMessageBoxDialogViewModel : public Object, public virtual IMessageBoxDialogViewModel
		{
		public:
			class Action : public Object, public virtual IMessageBoxDialogAction
			{
			public:
				FakeMessageBoxDialogViewModel*	viewModel;
				ButtonItem						button;

				Action(FakeMessageBoxDialogViewModel* _viewModel, ButtonItem _button)
					: viewModel(_viewModel)
					, button(_button)
				{
				}

				ButtonItem			GetButton() override					{ return button; }
				void				PerformAction() override				{ viewModel->result = Ptr(this); }
			};

			WString					text;
			WString					title;
			Icon					icon;
			ButtonItemList			buttons;
			ButtonItem				defaultButton;
			ButtonItem				result;

			WString					GetText() override						{ return text; }
			WString					GetTitle() override						{ return title; }
			Icon					GetIcon() override						{ return icon; }
			const ButtonItemList&	GetButtons() override					{ return buttons; }
			ButtonItem				GetDefaultButton() override				{ return defaultButton; }
			ButtonItem				GetResult() override					{ return result; }
		};

/***********************************************************************
FakeDialogServiceBase
***********************************************************************/

		FakeDialogServiceBase::MessageBoxButtonsOutput FakeDialogServiceBase::ShowMessageBox(
			INativeWindow* window,
			const WString& text,
			const WString& title,
			MessageBoxButtonsInput buttons,
			MessageBoxDefaultButton defaultButton,
			MessageBoxIcons icon,
			MessageBoxModalOptions modal
		)
		{
			auto vm = Ptr(new FakeMessageBoxDialogViewModel);
			vm->text = text;
			vm->title = title;
			vm->icon = icon;

#define USE_BUTTON(NAME) vm->buttons.Add(Ptr(new FakeMessageBoxDialogViewModel::Action(vm.Obj(), INativeDialogService::Select##NAME)))
			switch (buttons)
			{
			case DisplayOK:						USE_BUTTON(OK);														break;
			case DisplayOKCancel:				USE_BUTTON(OK);		USE_BUTTON(Cancel);								break;
			case DisplayYesNo:					USE_BUTTON(Yes);	USE_BUTTON(No);									break;
			case DisplayYesNoCancel:			USE_BUTTON(Yes);	USE_BUTTON(No);			USE_BUTTON(Cancel);		break;
			case DisplayRetryCancel:			USE_BUTTON(Retry);	USE_BUTTON(Cancel);								break;
			case DisplayAbortRetryIgnore:		USE_BUTTON(Abort);	USE_BUTTON(Retry);		USE_BUTTON(Ignore);		break;
			case DisplayCancelTryAgainContinue:	USE_BUTTON(Cancel);	USE_BUTTON(TryAgain);	USE_BUTTON(Continue);	break;
			default:							USE_BUTTON(OK);														break;
			}
#undef USE_BUTTON

#define USE_DEFAULT_BUTTON(INDEX) if (vm->buttons.Count() > INDEX) vm->defaultButton = vm->buttons[INDEX]
			USE_DEFAULT_BUTTON(0);
			switch (defaultButton)
			{
			case DefaultSecond:					USE_DEFAULT_BUTTON(1); break;
			case DefaultThird:					USE_DEFAULT_BUTTON(2); break;
			default:;
			}
#undef USE_DEFAULT_BUTTON

			vm->result = vm->defaultButton;
			{
				auto owner = GetApplication()->GetWindowFromNative(window);
				auto dialog = CreateMessageBoxDialog(vm);
				ShowModalDialogAndDelete(vm, owner, dialog);
			}
			return vm->result->GetButton();
		}
	}
}

/***********************************************************************
.\UTILITIES\FAKESERVICES\DIALOGS\GUIFAKEDIALOGSERVICE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace controls;

/***********************************************************************
FakeDialogService
***********************************************************************/

		controls::GuiWindow* FakeDialogService::CreateMessageBoxDialog(Ptr< IMessageBoxDialogViewModel> viewModel)
		{
			return new gaclib_controls::MessageBoxWindow(viewModel);
		}

		controls::GuiWindow* FakeDialogService::CreateColorDialog(Ptr<IColorDialogViewModel> viewModel)
		{
			return new gaclib_controls::ColorDialogWindow(viewModel);
		}

		controls::GuiWindow* FakeDialogService::CreateSimpleFontDialog(Ptr<ISimpleFontDialogViewModel> viewModel)
		{
			return new gaclib_controls::SimpleFontDialogWindow(viewModel);
		}

		controls::GuiWindow* FakeDialogService::CreateFullFontDialog(Ptr<IFullFontDialogViewModel> viewModel)
		{
			return new gaclib_controls::FullFontDialogWindow(viewModel);
		}

		controls::GuiWindow* FakeDialogService::CreateOpenFileDialog(Ptr<IFileDialogViewModel> viewModel)
		{
			auto dialog = new gaclib_controls::FileDialogWindow(viewModel);
			dialog->MakeOpenFileDialog();
			return dialog;
		}

		controls::GuiWindow* FakeDialogService::CreateSaveFileDialog(Ptr<IFileDialogViewModel> viewModel)
		{
			auto dialog = new gaclib_controls::FileDialogWindow(viewModel);
			dialog->MakeSaveFileDialog();
			return dialog;
		}

		FakeDialogService::FakeDialogService()
		{
		}

		FakeDialogService::~FakeDialogService()
		{
		}
	}
}

/***********************************************************************
.\UTILITIES\FAKESERVICES\DIALOGS\SOURCE\GUIFAKEDIALOGSERVICEUI.CPP
***********************************************************************/
/***********************************************************************
!!!!!! DO NOT MODIFY !!!!!!

Source: GacUI FakeDialogServiceUI

This file is generated by Workflow compiler
https://github.com/vczh-libraries
***********************************************************************/


#if defined( _MSC_VER)
#pragma warning(push)
#pragma warning(disable:4250)
#elif defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wparentheses-equality"
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#endif

#define GLOBAL_SYMBOL ::vl_workflow_global::GuiFakeDialogServiceUI::
#define GLOBAL_NAME ::vl_workflow_global::GuiFakeDialogServiceUI::Instance().
#define GLOBAL_OBJ &::vl_workflow_global::GuiFakeDialogServiceUI::Instance()

/***********************************************************************
Global Variables
***********************************************************************/

BEGIN_GLOBAL_STORAGE_CLASS(vl_workflow_global_GuiFakeDialogServiceUI)
	vl_workflow_global::GuiFakeDialogServiceUI instance;
	INITIALIZE_GLOBAL_STORAGE_CLASS

		instance.__vwsn_ls_DialogStrings = ::vl::reflection::description::IValueDictionary::Create();

		([]()
		{
			::gaclib_controls::DialogStrings::Install(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US")), ::gaclib_controls::DialogStrings::__vwsn_ls_en_US_BuildStrings(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US"))));
		}
		)();
	FINALIZE_GLOBAL_STORAGE_CLASS

		instance.__vwsn_ls_DialogStrings = nullptr;
END_GLOBAL_STORAGE_CLASS(vl_workflow_global_GuiFakeDialogServiceUI)

namespace vl_workflow_global
{
/***********************************************************************
Global Functions
***********************************************************************/

	GuiFakeDialogServiceUI& GuiFakeDialogServiceUI::Instance()
	{
		return Getvl_workflow_global_GuiFakeDialogServiceUI().instance;
	}

/***********************************************************************
Closures
***********************************************************************/

	//-------------------------------------------------------------------

	__vwsnf10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::__vwsnf10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetValue();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::presentation::Color>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetValue(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::__vwsnf11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetStrings();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IDialogStringsStrings>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetStrings(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::__vwsnf12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(::gaclib_controls::ColorDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_4)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_4)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::__vwsnf13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(::gaclib_controls::ColorDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->SetConfirmed(true);
		::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->SetColor(::vl::__vwsn::This(__vwsnthis_0->colorControl)->GetValue());
		::vl::__vwsn::This(__vwsnthis_0->self)->Close();
	}

	//-------------------------------------------------------------------

	__vwsnf14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::__vwsnf14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(::gaclib_controls::ColorDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_7)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_7)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf15_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::__vwsnf15_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(::gaclib_controls::ColorDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf15_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		::vl::__vwsn::This(__vwsnthis_0->self)->Close();
	}

	//-------------------------------------------------------------------

	__vwsnf16_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::__vwsnf16_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(::gaclib_controls::ColorDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf16_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf17_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::__vwsnf17_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(::gaclib_controls::ColorDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf17_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetStrings();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IDialogStringsStrings>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetStrings(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf18_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::__vwsnf18_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(::gaclib_controls::FileDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf18_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::operator()() const
	{
		::vl::__vwsn::This(::vl::presentation::controls::GetApplication())->InvokeInMainThread(::vl::__vwsn::This(__vwsnthis_0->self)->GetRelatedControlHost(), vl::Func(::vl_workflow_global::__vwsnf19_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__(__vwsnthis_0)));
	}

	//-------------------------------------------------------------------

	__vwsnf19_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__::__vwsnf19_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__(::gaclib_controls::FileDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf19_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__::operator()() const
	{
		::vl::__vwsn::This(__vwsnthis_0->self)->Close();
	}

	//-------------------------------------------------------------------

	__vwsnf1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_::__vwsnf1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_(::gaclib_controls::ColorComponentControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->textBox)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->textBox)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf20_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::__vwsnf20_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(::gaclib_controls::FileDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf20_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->buttonOK)->GetEnabled();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<bool>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->buttonOK)->SetEnabled(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf21_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::__vwsnf21_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(::gaclib_controls::FileDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf21_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		if (::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->TryConfirm(static_cast<::vl::presentation::controls::GuiWindow*>(__vwsnthis_0->self), ::vl::__vwsn::This(__vwsnthis_0->filePickerControl)->GetSelection()))
		{
			::vl::__vwsn::This(__vwsnthis_0->self)->Close();
		}
	}

	//-------------------------------------------------------------------

	__vwsnf22_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::__vwsnf22_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(::gaclib_controls::FileDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf22_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_6)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_6)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf23_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::__vwsnf23_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(::gaclib_controls::FileDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf23_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		::vl::__vwsn::This(__vwsnthis_0->self)->Close();
	}

	//-------------------------------------------------------------------

	__vwsnf24_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::__vwsnf24_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(::gaclib_controls::FileDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf24_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetStrings();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IDialogStringsStrings>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetStrings(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf25_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindow___vwsn_instance_ctor__::__vwsnf25_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindow___vwsn_instance_ctor__(::gaclib_controls::FileDialogWindow* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf25_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindow___vwsn_instance_ctor__::operator()() const
	{
		::vl::__vwsn::This(__vwsnthis_0->filePickerControl)->LocateSelectedFolderInTreeView();
	}

	//-------------------------------------------------------------------

	__vwsnf26_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf26_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	::vl::Ptr<::vl::reflection::description::IValueEnumerable> __vwsnf26_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_item_) const
	{
		auto item = ::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::IFileDialogFolder>>(__vwsn_item_);
		return ::vl::Ptr<::vl::reflection::description::IValueEnumerable>(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueObservableList>(::vl::__vwsn::This(item.Obj())->GetFolders()));
	}

	//-------------------------------------------------------------------

	__vwsnf27_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf27_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	::vl::WString __vwsnf27_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_item_) const
	{
		auto item = ::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::IFileDialogFolder>>(__vwsn_item_);
		return ::vl::__vwsn::This(item.Obj())->GetName();
	}

	//-------------------------------------------------------------------

	__vwsnf28_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf28_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	::vl::WString __vwsnf28_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_item_) const
	{
		auto item = ::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::IFileDialogFile>>(__vwsn_item_);
		return ::vl::__vwsn::This(item.Obj())->GetName();
	}

	//-------------------------------------------------------------------

	__vwsnf29_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf29_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	::vl::WString __vwsnf29_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_item_) const
	{
		auto item = ::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::IFileDialogFilter>>(__vwsn_item_);
		return ::vl::__vwsn::This(item.Obj())->GetName();
	}

	//-------------------------------------------------------------------

	__vwsnf2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_::__vwsnf2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_(::gaclib_controls::ColorComponentControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->textBox)->GetAlt();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->textBox)->SetAlt(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf30_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf30_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf30_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_2)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_2)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf32_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf32_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf32_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->dataGrid)->GetAdditionalFilter();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::controls::list::IDataFilter>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->dataGrid)->SetAdditionalFilter(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf33_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf33_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf33_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiKeyEventArgs* arguments) const
	{
		if (((((! ::vl::__vwsn::This(arguments)->ctrl) && (! ::vl::__vwsn::This(arguments)->shift)) && (! ::vl::__vwsn::This(arguments)->alt)) && (::vl::__vwsn::This(arguments)->code == ::vl::presentation::VKEY::KEY_RETURN)))
		{
			if (::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->TryConfirm(::vl::__vwsn::Ensure(::vl::__vwsn::RawPtrCast<::vl::presentation::controls::GuiWindow>(::vl::__vwsn::This(__vwsnthis_0->self)->GetRelatedControlHost())), ::vl::__vwsn::This(__vwsnthis_0->self)->GetSelection()))
			{
				::vl::__vwsn::EventInvoke(::vl::__vwsn::This(__vwsnthis_0->self)->RequestClose)();
			}
		}
	}

	//-------------------------------------------------------------------

	__vwsnf35_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf35_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf35_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		::vl::__vwsn::This(__vwsnthis_0->textBox)->SetText(::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->GetDisplayString(::vl::__vwsn::This(__vwsnthis_0->self)->GetSelectedFiles()));
		::vl::__vwsn::This(__vwsnthis_0->textBox)->SetCaret([&](){ ::vl::presentation::TextPos __vwsn_temp__; __vwsn_temp__.row = static_cast<::vl::vint>(0); __vwsn_temp__.column = static_cast<::vl::vint>(0); return __vwsn_temp__; }(), [&](){ ::vl::presentation::TextPos __vwsn_temp__; __vwsn_temp__.row = static_cast<::vl::vint>(0); __vwsn_temp__.column = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
	}

	//-------------------------------------------------------------------

	__vwsnf36_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf36_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf36_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiItemMouseEventArgs* arguments) const
	{
		auto file = ::vl::__vwsn::UnboxWeak<::vl::Ptr<::vl::presentation::IFileDialogFile>>(::vl::__vwsn::This(::vl::__vwsn::This(__vwsnthis_0->dataGrid)->GetItemProvider())->GetBindingValue(::vl::__vwsn::This(arguments)->itemIndex));
		auto selection = ::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->ParseDisplayString(::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->GetDisplayString(::vl::reflection::description::GetLazyList<::vl::Ptr<::vl::presentation::IFileDialogFile>>((::vl::__vwsn::CreateList().Add(file)).list)));
		::vl::__vwsn::This(::vl::presentation::controls::GetApplication())->InvokeInMainThread(::vl::__vwsn::This(__vwsnthis_0->self)->GetRelatedControlHost(), vl::Func(::vl_workflow_global::__vwsnf37_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__(selection, __vwsnthis_0)));
	}

	//-------------------------------------------------------------------

	__vwsnf37_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__::__vwsnf37_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__(::vl::collections::LazyList<::vl::WString> __vwsnctor_selection, ::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:selection(__vwsnctor_selection)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf37_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__::operator()() const
	{
		if (::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->TryConfirm(::vl::__vwsn::Ensure(::vl::__vwsn::RawPtrCast<::vl::presentation::controls::GuiWindow>(::vl::__vwsn::This(__vwsnthis_0->self)->GetRelatedControlHost())), this->selection))
		{
			::vl::__vwsn::EventInvoke(::vl::__vwsn::This(__vwsnthis_0->self)->RequestClose)();
		}
	}

	//-------------------------------------------------------------------

	__vwsnf38_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf38_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf38_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_17)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_17)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf39_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf39_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf39_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiKeyEventArgs* arguments) const
	{
		if (((((! ::vl::__vwsn::This(arguments)->ctrl) && (! ::vl::__vwsn::This(arguments)->shift)) && (! ::vl::__vwsn::This(arguments)->alt)) && (::vl::__vwsn::This(arguments)->code == ::vl::presentation::VKEY::KEY_RETURN)))
		{
			if (::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->TryConfirm(::vl::__vwsn::Ensure(::vl::__vwsn::RawPtrCast<::vl::presentation::controls::GuiWindow>(::vl::__vwsn::This(__vwsnthis_0->self)->GetRelatedControlHost())), ::vl::__vwsn::This(__vwsnthis_0->self)->GetSelection()))
			{
				::vl::__vwsn::EventInvoke(::vl::__vwsn::This(__vwsnthis_0->self)->RequestClose)();
			}
		}
	}

	//-------------------------------------------------------------------

	__vwsnf3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_::__vwsnf3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_(::gaclib_controls::ColorComponentControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		auto value = [&](){ try{ return ::vl::__vwsn::Parse<::vl::vint>(::vl::__vwsn::This(__vwsnthis_0->textBox)->GetText()); } catch(...){ return (- static_cast<::vl::vint>(1)); } }();
		if ((value == (- static_cast<::vl::vint>(1))))
		{
			return;
		}
		else if ((value < static_cast<::vl::vint>(0)))
		{
			::vl::__vwsn::This(__vwsnthis_0->tracker)->SetPosition(static_cast<::vl::vint>(0));
		}
		else if ((value > static_cast<::vl::vint>(255)))
		{
			::vl::__vwsn::This(__vwsnthis_0->tracker)->SetPosition(static_cast<::vl::vint>(255));
		}
		else
		{
			::vl::__vwsn::This(__vwsnthis_0->tracker)->SetPosition(value);
		}
	}

	//-------------------------------------------------------------------

	__vwsnf40_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf40_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf40_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_24.Obj())->GetSelectedFilter();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::IFileDialogFilter>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_24.Obj())->SetSelectedFilter(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf41_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf41_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf41_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_24.Obj())->GetSelectedFolder();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::IFileDialogFolder>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_24.Obj())->SetSelectedFolder(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf42_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf42_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf42_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()() const
	{
		::vl::__vwsn::This(__vwsnthis_0->self)->LocateSelectedFolderInTreeView();
	}

	//-------------------------------------------------------------------

	__vwsnf43_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf43_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf43_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()() const
	{
		if ((! ::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->GetIsLoadingFiles()))
		{
			::vl::__vwsn::This(__vwsnthis_0->dataGrid)->SetViewPosition([&](){ ::vl::presentation::Point __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(0); __vwsn_temp__.y = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
	}

	//-------------------------------------------------------------------

	__vwsnf44_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsnf44_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf44_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetStrings();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IDialogStringsStrings>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetStrings(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf45_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles_::__vwsnf45_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles_(::gaclib_controls::FilePickerControl* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	::vl::Ptr<::vl::reflection::description::ICoroutine> __vwsnf45_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles_::operator()(::vl::reflection::description::EnumerableCoroutine::IImpl* __vwsn_co_impl_) const
	{
		return ::vl::Ptr<::vl::reflection::description::ICoroutine>(new ::vl_workflow_global::__vwsnc24_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles___vl_reflection_description_ICoroutine(__vwsn_co_impl_, __vwsnthis_0));
	}

	//-------------------------------------------------------------------

	__vwsnf47_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::__vwsnf47_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(::gaclib_controls::FontNameControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf47_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		if (((::vl::__vwsn::This(__vwsnthis_0->textList)->GetSelectedItemIndex() != (- static_cast<::vl::vint>(1))) && (::vl::__vwsn::This(__vwsnthis_0->textBox)->GetText() != ::vl::__vwsn::This(__vwsnthis_0->textList)->GetSelectedItemText())))
		{
			::vl::__vwsn::This(__vwsnthis_0->textBox)->SetText(::vl::__vwsn::This(__vwsnthis_0->textList)->GetSelectedItemText());
		}
	}

	//-------------------------------------------------------------------

	__vwsnf48_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::__vwsnf48_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(::gaclib_controls::FontNameControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf48_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_0)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_0)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf49_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::__vwsnf49_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(::gaclib_controls::FontNameControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf49_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetValue();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetValue(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf4_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_::__vwsnf4_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_(::gaclib_controls::ColorComponentControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf4_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetValue();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::vint>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetValue(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf50_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::__vwsnf50_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(::gaclib_controls::FontNameControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf50_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetLegal();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<bool>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetLegal(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf51_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::__vwsnf51_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(::gaclib_controls::FontNameControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf51_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::operator()() const
	{
		::vl::__vwsn::This(__vwsnthis_0->self)->UpdateSelectedIndex();
	}

	//-------------------------------------------------------------------

	__vwsnf52_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::__vwsnf52_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(::gaclib_controls::FontNameControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf52_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetStrings();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IDialogStringsStrings>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetStrings(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf54_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::__vwsnf54_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(::gaclib_controls::FontSizeControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf54_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		if (((::vl::__vwsn::This(__vwsnthis_0->textList)->GetSelectedItemIndex() != (- static_cast<::vl::vint>(1))) && (::vl::__vwsn::This(__vwsnthis_0->textBox)->GetText() != ::vl::__vwsn::This(__vwsnthis_0->textList)->GetSelectedItemText())))
		{
			::vl::__vwsn::This(__vwsnthis_0->textBox)->SetText(::vl::__vwsn::This(__vwsnthis_0->textList)->GetSelectedItemText());
		}
	}

	//-------------------------------------------------------------------

	__vwsnf55_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::__vwsnf55_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(::gaclib_controls::FontSizeControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf55_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_0)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_0)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf56_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::__vwsnf56_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(::gaclib_controls::FontSizeControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf56_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetValue();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::vint>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetValue(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf57_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::__vwsnf57_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(::gaclib_controls::FontSizeControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf57_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetLegal();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<bool>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetLegal(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf58_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::__vwsnf58_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(::gaclib_controls::FontSizeControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf58_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::operator()() const
	{
		::vl::__vwsn::This(__vwsnthis_0->self)->UpdateSelectedIndex();
	}

	//-------------------------------------------------------------------

	__vwsnf59_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::__vwsnf59_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(::gaclib_controls::FontSizeControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf59_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetStrings();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IDialogStringsStrings>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetStrings(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::__vwsnf5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_2)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_2)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf60_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf60_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf60_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->checkBold)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->checkBold)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf61_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf61_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf61_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->checkItalic)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->checkItalic)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf62_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf62_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf62_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->checkUnderline)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->checkUnderline)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf63_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf63_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf63_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->checkStrikeline)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->checkStrikeline)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf64_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf64_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf64_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->checkHAA)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->checkHAA)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf65_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf65_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf65_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->checkVAA)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->checkVAA)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf66_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf66_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf66_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_8)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_8)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf67_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf67_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf67_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiMouseEventArgs* arguments) const
	{
		if (::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->SelectColor(static_cast<::vl::presentation::controls::GuiWindow*>(__vwsnthis_0->self)))
		{
			::vl::__vwsn::This(__vwsnthis_0->colorBackground.Obj())->SetColor(::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->GetColor());
		}
	}

	//-------------------------------------------------------------------

	__vwsnf68_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf68_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf68_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_18)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_18)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf69_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf69_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf69_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_26)->GetFont();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Nullable<::vl::presentation::FontProperties>>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_26)->SetFont(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::__vwsnf6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_4)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_4)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf70_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf70_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf70_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_23)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_23)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf71_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf71_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf71_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_30)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_30)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf72_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf72_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf72_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_30)->GetEnabled();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<bool>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_30)->SetEnabled(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf73_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf73_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf73_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->SetConfirmed(true);
		::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->SetFont([&](){ ::vl::presentation::FontProperties __vwsn_temp__; __vwsn_temp__.fontFamily = ::vl::__vwsn::This(__vwsnthis_0->nameControl)->GetValue(); __vwsn_temp__.size = ::vl::__vwsn::This(__vwsnthis_0->sizeControl)->GetValue(); __vwsn_temp__.bold = ::vl::__vwsn::This(__vwsnthis_0->checkBold)->GetSelected(); __vwsn_temp__.italic = ::vl::__vwsn::This(__vwsnthis_0->checkItalic)->GetSelected(); __vwsn_temp__.underline = ::vl::__vwsn::This(__vwsnthis_0->checkUnderline)->GetSelected(); __vwsn_temp__.strikeline = ::vl::__vwsn::This(__vwsnthis_0->checkStrikeline)->GetSelected(); __vwsn_temp__.antialias = ::vl::__vwsn::This(__vwsnthis_0->checkHAA)->GetSelected(); __vwsn_temp__.verticalAntialias = ::vl::__vwsn::This(__vwsnthis_0->checkVAA)->GetSelected(); return __vwsn_temp__; }());
		::vl::__vwsn::This(__vwsnthis_0->self)->Close();
	}

	//-------------------------------------------------------------------

	__vwsnf74_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf74_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf74_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_33)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_33)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf75_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf75_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf75_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		::vl::__vwsn::This(__vwsnthis_0->self)->Close();
	}

	//-------------------------------------------------------------------

	__vwsnf76_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf76_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf76_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf77_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::__vwsnf77_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf77_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetStrings();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IDialogStringsStrings>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetStrings(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf78_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::__vwsnf78_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf78_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_11)->GetFont();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Nullable<::vl::presentation::FontProperties>>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_11)->SetFont(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf79_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::__vwsnf79_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf79_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_8)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_8)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::__vwsnf7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_6)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_6)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf80_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::__vwsnf80_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf80_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_15)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_15)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf81_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::__vwsnf81_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf81_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_15)->GetEnabled();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<bool>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_15)->SetEnabled(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf82_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::__vwsnf82_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf82_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->SetConfirmed(true);
		::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->SetFontFamily(::vl::__vwsn::This(__vwsnthis_0->nameControl)->GetValue());
		::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->SetFontSize(::vl::__vwsn::This(__vwsnthis_0->sizeControl)->GetValue());
		::vl::__vwsn::This(__vwsnthis_0->self)->Close();
	}

	//-------------------------------------------------------------------

	__vwsnf83_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::__vwsnf83_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf83_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_18)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_18)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf84_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::__vwsnf84_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf84_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		::vl::__vwsn::This(__vwsnthis_0->self)->Close();
	}

	//-------------------------------------------------------------------

	__vwsnf85_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::__vwsnf85_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf85_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf86_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::__vwsnf86_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf86_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetStrings();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IDialogStringsStrings>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetStrings(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf87_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_::__vwsnf87_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_(::gaclib_controls::MessageBoxButtonTemplateConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf87_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->buttonControl)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->buttonControl)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf88_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_::__vwsnf88_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_(::gaclib_controls::MessageBoxButtonTemplateConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf88_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_::operator()(::vl::presentation::compositions::GuiGraphicsComposition* sender, ::vl::presentation::compositions::GuiEventArgs* arguments) const
	{
		::vl::__vwsn::This(__vwsnthis_0->Action.Obj())->PerformAction();
		::vl::__vwsn::This(::vl::__vwsn::This(__vwsnthis_0->self)->GetRelatedControlHost())->Close();
	}

	//-------------------------------------------------------------------

	__vwsnf89_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_::__vwsnf89_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_(::gaclib_controls::MessageBoxButtonTemplateConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf89_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetStrings();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IDialogStringsStrings>>(__vwsn_value_);
		if ((__vwsn_old_.Obj() == __vwsn_new_.Obj()))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->self)->SetStrings(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::__vwsnf8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_8)->GetText();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_8)->SetText(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsnf90_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxWindowConstructor___vwsn_gaclib_controls_MessageBoxWindow_Initialize_::__vwsnf90_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxWindowConstructor___vwsn_gaclib_controls_MessageBoxWindow_Initialize_(::gaclib_controls::MessageBoxWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	::vl::presentation::templates::GuiTemplate* __vwsnf90_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxWindowConstructor___vwsn_gaclib_controls_MessageBoxWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_viewModel_) const
	{
		{
			if ([&](){ auto __vwsn_temp__ = __vwsn_viewModel_; return __vwsn_temp__.GetSharedPtr() && ::vl::__vwsn::RawPtrCast<::vl::presentation::IMessageBoxDialogAction>(__vwsn_temp__.GetRawPtr()) != nullptr; }())
			{
				return static_cast<::vl::presentation::templates::GuiTemplate*>(new ::gaclib_controls::MessageBoxButtonTemplate(::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::IMessageBoxDialogAction>>(__vwsn_viewModel_)));
			}
		}
		throw ::vl::Exception(::vl::WString::Unmanaged(L"Cannot find a matched control template to create."));
	}

	//-------------------------------------------------------------------

	__vwsnf9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::__vwsnf9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnf9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const
	{
		auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_16.Obj())->GetColor();
		auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::presentation::Color>(__vwsn_value_);
		if ((__vwsn_old_ == __vwsn_new_))
		{
			return;
		}
		::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_16.Obj())->SetColor(__vwsn_new_);
	}

	//-------------------------------------------------------------------

	__vwsno31_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsno31_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	::vl::Ptr<::vl::presentation::GuiImageData> __vwsno31_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsno_1) const
	{
		return [&](auto node){ return ((::vl::__vwsn::This(node.Obj())->GetType() == ::vl::presentation::FileDialogFolderType::Folder) ? ::vl::__vwsn::This(__vwsnthis_0->self)->imageFolder : ::vl::Ptr<::vl::presentation::GuiImageData>()); }(::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::IFileDialogFolder>>(__vwsno_1));
	}

	//-------------------------------------------------------------------

	__vwsno34_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::__vwsno34_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	::vl::Ptr<::vl::presentation::GuiImageData> __vwsno34_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsno_1) const
	{
		return [&](auto node){ return ((::vl::__vwsn::This(node.Obj())->GetType() == ::vl::presentation::FileDialogFileType::Folder) ? ::vl::__vwsn::This(__vwsnthis_0->self)->imageFolder : ((::vl::__vwsn::This(node.Obj())->GetType() == ::vl::presentation::FileDialogFileType::File) ? ::vl::__vwsn::This(__vwsnthis_0->self)->imageFile : ::vl::Ptr<::vl::presentation::GuiImageData>())); }(::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::IFileDialogFile>>(__vwsno_1));
	}

	//-------------------------------------------------------------------

	__vwsno46_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::__vwsno46_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(::gaclib_controls::FontNameControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	::vl::WString __vwsno46_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsno_1) const
	{
		return ::vl::__vwsn::Unbox<::vl::WString>(__vwsno_1);
	}

	//-------------------------------------------------------------------

	__vwsno53_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::__vwsno53_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(::gaclib_controls::FontSizeControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	::vl::WString __vwsno53_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsno_1) const
	{
		return ::vl::__vwsn::ToString(::vl::__vwsn::Unbox<::vl::vint>(__vwsno_1));
	}

	//-------------------------------------------------------------------

	__vwsnc10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::gaclib_controls::DialogStrings::Get(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLocale());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return ::vl::presentation::controls::GetApplication(); } catch(...){ return static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, ::vl::Func<void()>(this, &__vwsnc10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::ColorDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->OK();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::ColorDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::ColorDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Cancel();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::ColorDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::ColorDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->ColorDialogTitle();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::ColorDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::gaclib_controls::DialogStrings::Get(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLocale());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return ::vl::presentation::controls::GetApplication(); } catch(...){ return static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, ::vl::Func<void()>(this, &__vwsnc14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc15_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc15_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FileDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = ::vl::Ptr<::vl::presentation::IFileDialogViewModel>();
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc15_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = (! ::vl::__vwsn::This(__vwsn_bind_cache_0.Obj())->GetIsLoadingFiles());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc15_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc15_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->ViewModel; } catch(...){ return ::vl::Ptr<::vl::presentation::IFileDialogViewModel>(); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0.Obj())->IsLoadingFilesChanged, ::vl::Func<void()>(this, &__vwsnc15_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc15_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc15_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0.Obj())->IsLoadingFilesChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = ::vl::Ptr<::vl::presentation::IFileDialogViewModel>());
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc16_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc16_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FileDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FileDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FileDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc16_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Cancel();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc16_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc16_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FileDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc16_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc16_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc16_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FileDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc17_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc17_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FileDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc17_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::gaclib_controls::DialogStrings::Get(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLocale());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc17_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc17_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return ::vl::presentation::controls::GetApplication(); } catch(...){ return static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, ::vl::Func<void()>(this, &__vwsnc17_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc17_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc17_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc18_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc18_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = ::vl::Ptr<::vl::presentation::IFileDialogViewModel>();
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc18_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = [&](){ try{ return ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0.Obj())->GetSelectedFolder().Obj())->GetFullPath(); } catch(...){ return ::vl::WString::Unmanaged(L""); } }();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc18_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc18_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->ViewModel; } catch(...){ return ::vl::Ptr<::vl::presentation::IFileDialogViewModel>(); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0.Obj())->SelectedFolderChanged, ::vl::Func<void()>(this, &__vwsnc18_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc18_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc18_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0.Obj())->SelectedFolderChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = ::vl::Ptr<::vl::presentation::IFileDialogViewModel>());
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc19_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc19_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = ::vl::Ptr<::vl::presentation::IFileDialogViewModel>();
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc19_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(__vwsnthis_0->self)->CreateFileFilter(::vl::__vwsn::This(__vwsn_bind_cache_0.Obj())->GetSelectedFilter());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc19_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc19_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->ViewModel; } catch(...){ return ::vl::Ptr<::vl::presentation::IFileDialogViewModel>(); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0.Obj())->SelectedFilterChanged, ::vl::Func<void()>(this, &__vwsnc19_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc19_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc19_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0.Obj())->SelectedFilterChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = ::vl::Ptr<::vl::presentation::IFileDialogViewModel>());
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorComponentControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorComponentControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::ToString(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetValue());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->self; } catch(...){ return static_cast<::gaclib_controls::ColorComponentControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->ValueChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorComponentControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc20_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc20_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FilePickerControl* __vwsnctor___vwsn_this_, ::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FilePickerControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc20_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->FileDialogFileName();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc20_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc20_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FilePickerControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc20_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc20_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc20_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FilePickerControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc21_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc21_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiComboBoxListControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc21_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::UnboxWeak<::vl::Ptr<::vl::presentation::IFileDialogFilter>>(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetSelectedItem());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc21_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc21_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->comboBox; } catch(...){ return static_cast<::vl::presentation::controls::GuiComboBoxListControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->SelectedIndexChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc21_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc21_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc21_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->SelectedIndexChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiComboBoxListControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc22_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc22_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiBindableTreeView*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc22_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::UnboxWeak<::vl::Ptr<::vl::presentation::IFileDialogFolder>>(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetSelectedItem());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc22_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc22_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->treeView; } catch(...){ return static_cast<::vl::presentation::controls::GuiBindableTreeView*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->SelectionChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc22_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc22_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc22_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->SelectionChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiBindableTreeView*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc23_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc23_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FilePickerControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc23_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::gaclib_controls::DialogStrings::Get(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLocale());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc23_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc23_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return ::vl::presentation::controls::GetApplication(); } catch(...){ return static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, ::vl::Func<void()>(this, &__vwsnc23_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc23_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc23_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc24_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles___vl_reflection_description_ICoroutine::__vwsnc24_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles___vl_reflection_description_ICoroutine(::vl::reflection::description::EnumerableCoroutine::IImpl* __vwsnctor___vwsn_co_impl_, ::gaclib_controls::FilePickerControl* __vwsnctorthis_0)
		:__vwsn_co_impl_(__vwsnctor___vwsn_co_impl_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_co0_file = ::vl::Ptr<::vl::presentation::IFileDialogFile>();
		this->__vwsn_co1_item = static_cast<::vl::vint>(0);
		this->__vwsn_co2_for_enumerable_item = ::vl::Ptr<::vl::reflection::description::IValueEnumerable>();
		this->__vwsn_co3_for_enumerator_item = ::vl::Ptr<::vl::reflection::description::IValueEnumerator>();
		this->__vwsn_co_state_ = static_cast<::vl::vint>(0);
		this->__vwsn_co_state_before_pause_ = (- static_cast<::vl::vint>(1));
		this->__vwsn_prop_Failure = ::vl::Ptr<::vl::reflection::description::IValueException>();
		this->__vwsn_prop_Status = ::vl::reflection::description::CoroutineStatus::Waiting;
	}

	::vl::Ptr<::vl::reflection::description::IValueException> __vwsnc24_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles___vl_reflection_description_ICoroutine::GetFailure()
	{
		return __vwsn_prop_Failure;
	}
	void __vwsnc24_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles___vl_reflection_description_ICoroutine::SetFailure(::vl::Ptr<::vl::reflection::description::IValueException> __vwsn_value_)
	{
		(__vwsn_prop_Failure = __vwsn_value_);
	}

	::vl::reflection::description::CoroutineStatus __vwsnc24_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles___vl_reflection_description_ICoroutine::GetStatus()
	{
		return __vwsn_prop_Status;
	}
	void __vwsnc24_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles___vl_reflection_description_ICoroutine::SetStatus(::vl::reflection::description::CoroutineStatus __vwsn_value_)
	{
		(__vwsn_prop_Status = __vwsn_value_);
	}

	void __vwsnc24_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles___vl_reflection_description_ICoroutine::Resume(bool __vwsn_raise_exception_, ::vl::Ptr<::vl::reflection::description::CoroutineResult> __vwsn_co_result_)
	{
		if ((this->GetStatus() != ::vl::reflection::description::CoroutineStatus::Waiting))
		{
			throw ::vl::Exception(::vl::WString::Unmanaged(L"Resume should be called only when the coroutine is in the waiting status."));
		}
		this->SetStatus(::vl::reflection::description::CoroutineStatus::Executing);
		try
		{
			{
				if ((__vwsn_co_state_before_pause_ != (- static_cast<::vl::vint>(1))))
				{
					if ((! static_cast<bool>(__vwsn_co_result_)))
					{
						(__vwsn_co_state_before_pause_ = (- static_cast<::vl::vint>(1)));
					}
					else if ((! static_cast<bool>(::vl::__vwsn::This(__vwsn_co_result_.Obj())->GetFailure())))
					{
						(__vwsn_co_state_before_pause_ = (- static_cast<::vl::vint>(1)));
					}
					else
					{
						{
							(__vwsn_co_state_before_pause_ = (- static_cast<::vl::vint>(1)));
							throw ::vl::Exception(::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_co_result_.Obj())->GetFailure().Obj())->GetMessage());
						}
					}
				}
				while (true)
				{
					if ((__vwsn_co_state_ == static_cast<::vl::vint>(0)))
					{
						(__vwsn_co2_for_enumerable_item = ::vl::Ptr<::vl::reflection::description::IValueEnumerable>(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueReadonlyList>(::vl::__vwsn::This(__vwsnthis_0->dataGrid)->GetSelectedItems())));
						(__vwsn_co3_for_enumerator_item = ::vl::__vwsn::This(__vwsn_co2_for_enumerable_item.Obj())->CreateEnumerator());
						if (::vl::__vwsn::This(__vwsn_co3_for_enumerator_item.Obj())->Next())
						{
							(__vwsn_co_state_ = static_cast<::vl::vint>(3));
							continue;
						}
						(__vwsn_co_state_ = static_cast<::vl::vint>(1));
						continue;
					}
					if ((__vwsn_co_state_ == static_cast<::vl::vint>(1)))
					{
						this->SetStatus(::vl::reflection::description::CoroutineStatus::Stopped);
						return;
					}
					if ((__vwsn_co_state_ == static_cast<::vl::vint>(2)))
					{
						if (::vl::__vwsn::This(__vwsn_co3_for_enumerator_item.Obj())->Next())
						{
							(__vwsn_co_state_ = static_cast<::vl::vint>(3));
							continue;
						}
						(__vwsn_co_state_ = static_cast<::vl::vint>(1));
						continue;
					}
					if ((__vwsn_co_state_ == static_cast<::vl::vint>(3)))
					{
						(__vwsn_co1_item = ::vl::__vwsn::Unbox<::vl::vint>(::vl::__vwsn::This(__vwsn_co3_for_enumerator_item.Obj())->GetCurrent()));
						(__vwsn_co0_file = ::vl::__vwsn::UnboxWeak<::vl::Ptr<::vl::presentation::IFileDialogFile>>(::vl::__vwsn::This(::vl::__vwsn::This(__vwsnthis_0->dataGrid)->GetItemProvider())->GetBindingValue(__vwsn_co1_item)));
						if (static_cast<bool>(__vwsn_co0_file))
						{
							this->SetStatus(::vl::reflection::description::CoroutineStatus::Waiting);
							(__vwsn_co_state_before_pause_ = __vwsn_co_state_);
							(__vwsn_co_state_ = static_cast<::vl::vint>(4));
							{
								::vl::reflection::description::EnumerableCoroutine::YieldAndPause(__vwsn_co_impl_, ::vl::__vwsn::Box(__vwsn_co0_file));
							}
							return;
						}
						(__vwsn_co_state_ = static_cast<::vl::vint>(2));
						continue;
					}
					if ((__vwsn_co_state_ == static_cast<::vl::vint>(4)))
					{
						if (static_cast<bool>(__vwsn_co_result_))
						{
							if (static_cast<bool>(::vl::__vwsn::This(__vwsn_co_result_.Obj())->GetFailure()))
							{
								throw ::vl::Exception(::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_co_result_.Obj())->GetFailure().Obj())->GetMessage());
							}
						}
						(__vwsn_co_state_ = static_cast<::vl::vint>(2));
						continue;
					}
				}
			}
		}
		catch(const ::vl::Exception& __vwsne_0)
		{
			auto __vwsn_co_ex_ = ::vl::reflection::description::IValueException::Create(__vwsne_0.Message());
			{
				this->SetFailure(__vwsn_co_ex_);
				this->SetStatus(::vl::reflection::description::CoroutineStatus::Stopped);
				if (__vwsn_raise_exception_)
				{
					throw;
				}
			}
		}
	}

	//-------------------------------------------------------------------

	__vwsnc25_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_CreateFileFilter__vl_presentation_controls_list_IDataFilter::__vwsnc25_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_CreateFileFilter__vl_presentation_controls_list_IDataFilter(::vl::Ptr<::vl::presentation::IFileDialogFilter> __vwsnctor_filter, ::gaclib_controls::FilePickerControl* __vwsnctorthis_0)
		:filter(__vwsnctor_filter)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
	}

	void __vwsnc25_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_CreateFileFilter__vl_presentation_controls_list_IDataFilter::SetCallback(::vl::presentation::controls::list::IDataProcessorCallback* value)
	{
	}

	bool __vwsnc25_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_CreateFileFilter__vl_presentation_controls_list_IDataFilter::Filter(const ::vl::reflection::description::Value& row)
	{
		return ::vl::__vwsn::This(filter.Obj())->FilterFile(::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::IFileDialogFile>>(row));
	}

	//-------------------------------------------------------------------

	__vwsnc26_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc26_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FontNameControl* __vwsnctor___vwsn_this_, ::gaclib_controls::FontNameControlConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontNameControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc26_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->FontNameGroup();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc26_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc26_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FontNameControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc26_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc26_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc26_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontNameControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc27_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc27_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FontNameControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc27_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(__vwsn_bind_cache_0)->GetText();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc27_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc27_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->textBox; } catch(...){ return static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->TextChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc27_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc27_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc27_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->TextChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc28_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc28_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FontNameControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc28_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ((! ::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->GetFontMustExist()) || (::vl::__vwsn::This(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueReadonlyList>(::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->GetFontList()).Obj())->IndexOf(::vl::__vwsn::Box(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetText())) != (- static_cast<::vl::vint>(1))));
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc28_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc28_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->textBox; } catch(...){ return static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->TextChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc28_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc28_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc28_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->TextChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc29_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc29_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FontNameControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc29_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::gaclib_controls::DialogStrings::Get(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLocale());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc29_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc29_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return ::vl::presentation::controls::GetApplication(); } catch(...){ return static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, ::vl::Func<void()>(this, &__vwsnc29_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc29_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc29_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorComponentControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorComponentControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(__vwsn_bind_cache_0)->GetTextBoxAlt();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->self; } catch(...){ return static_cast<::gaclib_controls::ColorComponentControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->TextBoxAltChanged, ::vl::Func<void()>(this, &__vwsnc2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->TextBoxAltChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorComponentControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc30_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc30_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FontSizeControl* __vwsnctor___vwsn_this_, ::gaclib_controls::FontSizeControlConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc30_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->FontSizeGroup();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc30_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc30_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FontSizeControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc30_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc30_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc30_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc31_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc31_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FontSizeControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc31_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = [&](){ try{ return ::vl::__vwsn::Parse<::vl::vint>(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetText()); } catch(...){ return (- static_cast<::vl::vint>(1)); } }();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc31_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc31_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->textBox; } catch(...){ return static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->TextChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc31_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc31_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc31_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->TextChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc32_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc32_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FontSizeControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc32_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = (::vl::__vwsn::This(__vwsn_bind_cache_0)->GetValue() > static_cast<::vl::vint>(0));
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc32_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc32_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->self; } catch(...){ return static_cast<::gaclib_controls::FontSizeControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc32_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc32_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc32_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->ValueChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc33_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc33_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FontSizeControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc33_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::gaclib_controls::DialogStrings::Get(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLocale());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc33_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc33_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return ::vl::presentation::controls::GetApplication(); } catch(...){ return static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, ::vl::Func<void()>(this, &__vwsnc33_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc33_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc33_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc34_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc34_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc34_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Bold();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc34_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc34_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc34_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc34_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc34_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc35_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc35_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc35_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Italic();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc35_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc35_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc35_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc35_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc35_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc36_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc36_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc36_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Underline();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc36_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc36_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc36_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc36_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc36_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc37_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc37_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc37_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Strikeline();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc37_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc37_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc37_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc37_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc37_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc38_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc38_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc38_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->HAA();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc38_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc38_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc38_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc38_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc38_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc39_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc39_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc39_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->VAA();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc39_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc39_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc39_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc39_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc39_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorComponentControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiScroll*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(__vwsn_bind_cache_0)->GetPosition();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->tracker; } catch(...){ return static_cast<::vl::presentation::controls::GuiScroll*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->PositionChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->PositionChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiScroll*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc40_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc40_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc40_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->FontEffectGroup();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc40_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc40_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc40_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc40_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc40_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc41_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc41_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc41_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->FontColorGroup();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc41_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc41_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc41_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc41_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc41_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontNameControl*>(nullptr);
		this->__vwsn_bind_cache_1 = static_cast<::gaclib_controls::FontNameControl*>(nullptr);
		this->__vwsn_bind_cache_2 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr);
		this->__vwsn_bind_cache_3 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr);
		this->__vwsn_bind_cache_4 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr);
		this->__vwsn_bind_cache_5 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr);
		this->__vwsn_bind_cache_6 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr);
		this->__vwsn_bind_cache_7 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr);
		this->__vwsn_bind_cache_8 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr);
		this->__vwsn_bind_cache_9 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_2_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_3_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_4_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_5_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_6_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_7_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_8_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_9_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = [&](auto defaultFont){ return [&](){ ::vl::presentation::FontProperties __vwsn_temp__; __vwsn_temp__.fontFamily = (::vl::__vwsn::This(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueReadonlyList>(::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->GetFontList()).Obj())->Contains(::vl::__vwsn::Box(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetValue())) ? ::vl::__vwsn::This(__vwsn_bind_cache_1)->GetValue() : defaultFont.fontFamily); __vwsn_temp__.size = ((::vl::__vwsn::This(__vwsn_bind_cache_2)->GetValue() > static_cast<::vl::vint>(0)) ? ::vl::__vwsn::This(__vwsn_bind_cache_3)->GetValue() : defaultFont.size); __vwsn_temp__.bold = ::vl::__vwsn::This(__vwsn_bind_cache_4)->GetSelected(); __vwsn_temp__.italic = ::vl::__vwsn::This(__vwsn_bind_cache_5)->GetSelected(); __vwsn_temp__.underline = ::vl::__vwsn::This(__vwsn_bind_cache_6)->GetSelected(); __vwsn_temp__.strikeline = ::vl::__vwsn::This(__vwsn_bind_cache_7)->GetSelected(); __vwsn_temp__.antialias = ::vl::__vwsn::This(__vwsn_bind_cache_8)->GetSelected(); __vwsn_temp__.verticalAntialias = ::vl::__vwsn::This(__vwsn_bind_cache_9)->GetSelected(); return __vwsn_temp__; }(); }(::vl::__vwsn::This(::vl::__vwsn::This(::vl::presentation::GetCurrentController())->ResourceService())->GetDefaultFont());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_1_0()
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_2_0()
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_3_0()
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_4_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_5_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_6_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_7_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_8_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_9_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1)
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->nameControl; } catch(...){ return static_cast<::gaclib_controls::FontNameControl*>(nullptr); } }());
			(__vwsn_bind_cache_1 = [&](){ try{ return __vwsnthis_0->nameControl; } catch(...){ return static_cast<::gaclib_controls::FontNameControl*>(nullptr); } }());
			(__vwsn_bind_cache_2 = [&](){ try{ return __vwsnthis_0->sizeControl; } catch(...){ return static_cast<::gaclib_controls::FontSizeControl*>(nullptr); } }());
			(__vwsn_bind_cache_3 = [&](){ try{ return __vwsnthis_0->sizeControl; } catch(...){ return static_cast<::gaclib_controls::FontSizeControl*>(nullptr); } }());
			(__vwsn_bind_cache_4 = [&](){ try{ return __vwsnthis_0->checkBold; } catch(...){ return static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr); } }());
			(__vwsn_bind_cache_5 = [&](){ try{ return __vwsnthis_0->checkItalic; } catch(...){ return static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr); } }());
			(__vwsn_bind_cache_6 = [&](){ try{ return __vwsnthis_0->checkUnderline; } catch(...){ return static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr); } }());
			(__vwsn_bind_cache_7 = [&](){ try{ return __vwsnthis_0->checkStrikeline; } catch(...){ return static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr); } }());
			(__vwsn_bind_cache_8 = [&](){ try{ return __vwsnthis_0->checkHAA; } catch(...){ return static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr); } }());
			(__vwsn_bind_cache_9 = [&](){ try{ return __vwsnthis_0->checkVAA; } catch(...){ return static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_1_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_1)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_1_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_2_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_2)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_2_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_3_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_3)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_3_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_4_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_4)->SelectedChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_4_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_5_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_5)->SelectedChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_5_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_6_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_6)->SelectedChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_6_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_7_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_7)->SelectedChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_7_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_8_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_8)->SelectedChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_8_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_9_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_9)->SelectedChanged, ::vl::Func<void(::vl::presentation::compositions::GuiGraphicsComposition*, ::vl::presentation::compositions::GuiEventArgs*)>(this, &__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_9_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->ValueChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_1_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_1)->ValueChanged, __vwsn_bind_handler_1_0);
				(__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_2_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_2)->ValueChanged, __vwsn_bind_handler_2_0);
				(__vwsn_bind_handler_2_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_3_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_3)->ValueChanged, __vwsn_bind_handler_3_0);
				(__vwsn_bind_handler_3_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_4_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_4)->SelectedChanged, __vwsn_bind_handler_4_0);
				(__vwsn_bind_handler_4_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_5_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_5)->SelectedChanged, __vwsn_bind_handler_5_0);
				(__vwsn_bind_handler_5_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_6_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_6)->SelectedChanged, __vwsn_bind_handler_6_0);
				(__vwsn_bind_handler_6_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_7_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_7)->SelectedChanged, __vwsn_bind_handler_7_0);
				(__vwsn_bind_handler_7_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_8_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_8)->SelectedChanged, __vwsn_bind_handler_8_0);
				(__vwsn_bind_handler_8_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_9_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_9)->SelectedChanged, __vwsn_bind_handler_9_0);
				(__vwsn_bind_handler_9_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontNameControl*>(nullptr));
			(__vwsn_bind_cache_1 = static_cast<::gaclib_controls::FontNameControl*>(nullptr));
			(__vwsn_bind_cache_2 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr));
			(__vwsn_bind_cache_3 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr));
			(__vwsn_bind_cache_4 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr));
			(__vwsn_bind_cache_5 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr));
			(__vwsn_bind_cache_6 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr));
			(__vwsn_bind_cache_7 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr));
			(__vwsn_bind_cache_8 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr));
			(__vwsn_bind_cache_9 = static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_2_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_3_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_4_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_5_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_6_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_7_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_8_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_9_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc43_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc43_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc43_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->FontPreviewGroup();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc43_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc43_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc43_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc43_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc43_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc44_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc44_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc44_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->OK();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc44_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc44_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc44_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc44_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc44_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc45_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc45_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontNameControl*>(nullptr);
		this->__vwsn_bind_cache_1 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc45_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = (::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLegal() && ::vl::__vwsn::This(__vwsn_bind_cache_1)->GetLegal());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc45_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc45_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_1_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc45_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->nameControl; } catch(...){ return static_cast<::gaclib_controls::FontNameControl*>(nullptr); } }());
			(__vwsn_bind_cache_1 = [&](){ try{ return __vwsnthis_0->sizeControl; } catch(...){ return static_cast<::gaclib_controls::FontSizeControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LegalChanged, ::vl::Func<void()>(this, &__vwsnc45_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_1_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_1)->LegalChanged, ::vl::Func<void()>(this, &__vwsnc45_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_1_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc45_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc45_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LegalChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_1_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_1)->LegalChanged, __vwsn_bind_handler_1_0);
				(__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontNameControl*>(nullptr));
			(__vwsn_bind_cache_1 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc46_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc46_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc46_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Cancel();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc46_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc46_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc46_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc46_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc46_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc47_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc47_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc47_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->FontDialogTitle();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc47_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc47_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc47_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc47_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc47_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc48_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc48_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::FullFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc48_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::gaclib_controls::DialogStrings::Get(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLocale());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc48_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc48_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return ::vl::presentation::controls::GetApplication(); } catch(...){ return static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, ::vl::Func<void()>(this, &__vwsnc48_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc48_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc48_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontNameControl*>(nullptr);
		this->__vwsn_bind_cache_1 = static_cast<::gaclib_controls::FontNameControl*>(nullptr);
		this->__vwsn_bind_cache_2 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr);
		this->__vwsn_bind_cache_3 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_2_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_3_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = [&](auto defaultFont){ return [&](){ ::vl::presentation::FontProperties __vwsn_temp__; __vwsn_temp__.fontFamily = (::vl::__vwsn::This(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueReadonlyList>(::vl::__vwsn::This(__vwsnthis_0->ViewModel.Obj())->GetFontList()).Obj())->Contains(::vl::__vwsn::Box(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetValue())) ? ::vl::__vwsn::This(__vwsn_bind_cache_1)->GetValue() : defaultFont.fontFamily); __vwsn_temp__.size = ((::vl::__vwsn::This(__vwsn_bind_cache_2)->GetValue() > static_cast<::vl::vint>(0)) ? ::vl::__vwsn::This(__vwsn_bind_cache_3)->GetValue() : defaultFont.size); __vwsn_temp__.antialias = true; __vwsn_temp__.verticalAntialias = true; return __vwsn_temp__; }(); }(::vl::__vwsn::This(::vl::__vwsn::This(::vl::presentation::GetCurrentController())->ResourceService())->GetDefaultFont());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_1_0()
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_2_0()
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_3_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->nameControl; } catch(...){ return static_cast<::gaclib_controls::FontNameControl*>(nullptr); } }());
			(__vwsn_bind_cache_1 = [&](){ try{ return __vwsnthis_0->nameControl; } catch(...){ return static_cast<::gaclib_controls::FontNameControl*>(nullptr); } }());
			(__vwsn_bind_cache_2 = [&](){ try{ return __vwsnthis_0->sizeControl; } catch(...){ return static_cast<::gaclib_controls::FontSizeControl*>(nullptr); } }());
			(__vwsn_bind_cache_3 = [&](){ try{ return __vwsnthis_0->sizeControl; } catch(...){ return static_cast<::gaclib_controls::FontSizeControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_1_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_1)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_1_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_2_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_2)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_2_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_3_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_3)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_3_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->ValueChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_1_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_1)->ValueChanged, __vwsn_bind_handler_1_0);
				(__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_2_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_2)->ValueChanged, __vwsn_bind_handler_2_0);
				(__vwsn_bind_handler_2_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_3_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_3)->ValueChanged, __vwsn_bind_handler_3_0);
				(__vwsn_bind_handler_3_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontNameControl*>(nullptr));
			(__vwsn_bind_cache_1 = static_cast<::gaclib_controls::FontNameControl*>(nullptr));
			(__vwsn_bind_cache_2 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr));
			(__vwsn_bind_cache_3 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_2_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_3_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc4_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc4_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorDialogControl* __vwsnctor___vwsn_this_, ::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc4_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Red();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc4_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc4_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::ColorDialogControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc4_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc4_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc4_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc50_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc50_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::SimpleFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc50_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->FontPreviewGroup();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc50_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc50_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc50_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc50_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc50_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc51_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc51_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::SimpleFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc51_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->OK();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc51_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc51_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc51_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc51_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc51_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc52_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc52_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontNameControl*>(nullptr);
		this->__vwsn_bind_cache_1 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc52_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = (::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLegal() && ::vl::__vwsn::This(__vwsn_bind_cache_1)->GetLegal());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc52_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc52_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_1_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc52_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->nameControl; } catch(...){ return static_cast<::gaclib_controls::FontNameControl*>(nullptr); } }());
			(__vwsn_bind_cache_1 = [&](){ try{ return __vwsnthis_0->sizeControl; } catch(...){ return static_cast<::gaclib_controls::FontSizeControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LegalChanged, ::vl::Func<void()>(this, &__vwsnc52_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_1_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_1)->LegalChanged, ::vl::Func<void()>(this, &__vwsnc52_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_1_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc52_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc52_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LegalChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_1_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_1)->LegalChanged, __vwsn_bind_handler_1_0);
				(__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::FontNameControl*>(nullptr));
			(__vwsn_bind_cache_1 = static_cast<::gaclib_controls::FontSizeControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_1_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc53_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc53_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::SimpleFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc53_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Cancel();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc53_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc53_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc53_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc53_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc53_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc54_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc54_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::SimpleFontDialogWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc54_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->FontDialogTitle();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc54_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc54_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc54_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc54_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc54_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc55_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc55_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::SimpleFontDialogWindowConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc55_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::gaclib_controls::DialogStrings::Get(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLocale());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc55_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc55_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return ::vl::presentation::controls::GetApplication(); } catch(...){ return static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, ::vl::Func<void()>(this, &__vwsnc55_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc55_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc55_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc56_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::__vwsnc56_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::MessageBoxButtonTemplateConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::MessageBoxButtonTemplate*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc56_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetButtonText(::vl::__vwsn::This(__vwsnthis_0->Action.Obj())->GetButton(), ::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc56_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc56_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->self; } catch(...){ return static_cast<::gaclib_controls::MessageBoxButtonTemplate*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc56_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc56_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc56_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::MessageBoxButtonTemplate*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc57_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::__vwsnc57_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::MessageBoxButtonTemplateConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc57_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::gaclib_controls::DialogStrings::Get(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLocale());
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc57_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc57_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return ::vl::presentation::controls::GetApplication(); } catch(...){ return static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, ::vl::Func<void()>(this, &__vwsnc57_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc57_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc57_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::__vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings()
	{
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Abort()
	{
		return ::vl::WString::Unmanaged(L"Abort");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Blue()
	{
		return ::vl::WString::Unmanaged(L"Blue:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Bold()
	{
		return ::vl::WString::Unmanaged(L"Bold");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Cancel()
	{
		return ::vl::WString::Unmanaged(L"Cancel");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Color()
	{
		return ::vl::WString::Unmanaged(L"Color:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::ColorDialogTitle()
	{
		return ::vl::WString::Unmanaged(L"Choose Color");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Continue()
	{
		return ::vl::WString::Unmanaged(L"Continue");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogAskCreateFile()
	{
		return ::vl::WString::Unmanaged(L"Do you want to create the following file(s):");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogAskOverrideFile()
	{
		return ::vl::WString::Unmanaged(L"Do you want to override the following file(s):");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogErrorEmptySelection()
	{
		return ::vl::WString::Unmanaged(L"At least one file must be selected.");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogErrorFileExpected()
	{
		return ::vl::WString::Unmanaged(L"File(s) expected but folder(s) selected:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogErrorFileNotExist()
	{
		return ::vl::WString::Unmanaged(L"File(s) not exist:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogErrorFolderNotExist()
	{
		return ::vl::WString::Unmanaged(L"Folder not exist:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogErrorMultipleSelectionNotEnabled()
	{
		return ::vl::WString::Unmanaged(L"Multiple selection is not enabled in this dialog.");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogFileName()
	{
		return ::vl::WString::Unmanaged(L"File Name:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogOpen()
	{
		return ::vl::WString::Unmanaged(L"Open");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogSave()
	{
		return ::vl::WString::Unmanaged(L"Save");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogTextLoadingFiles()
	{
		return ::vl::WString::Unmanaged(L"(Loading Folders and Files...)");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FileDialogTextLoadingFolders()
	{
		return ::vl::WString::Unmanaged(L"(Loading...)");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FontColorGroup()
	{
		return ::vl::WString::Unmanaged(L"Color:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FontColorGroup2()
	{
		return ::vl::WString::Unmanaged(L"Pick a Color:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FontDialogTitle()
	{
		return ::vl::WString::Unmanaged(L"Choose Font");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FontEffectGroup()
	{
		return ::vl::WString::Unmanaged(L"Effect:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FontNameGroup()
	{
		return ::vl::WString::Unmanaged(L"Font:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FontPreviewGroup()
	{
		return ::vl::WString::Unmanaged(L"Preview:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::FontSizeGroup()
	{
		return ::vl::WString::Unmanaged(L"Size:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Green()
	{
		return ::vl::WString::Unmanaged(L"Green:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::HAA()
	{
		return ::vl::WString::Unmanaged(L"Horizontal Antialias");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Ignore()
	{
		return ::vl::WString::Unmanaged(L"Ignore");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Italic()
	{
		return ::vl::WString::Unmanaged(L"Italic");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::No()
	{
		return ::vl::WString::Unmanaged(L"No");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::OK()
	{
		return ::vl::WString::Unmanaged(L"OK");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Red()
	{
		return ::vl::WString::Unmanaged(L"Red:");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Retry()
	{
		return ::vl::WString::Unmanaged(L"Retry");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Strikeline()
	{
		return ::vl::WString::Unmanaged(L"Strike-through");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::TryAgain()
	{
		return ::vl::WString::Unmanaged(L"Try Again");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Underline()
	{
		return ::vl::WString::Unmanaged(L"Underline");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::VAA()
	{
		return ::vl::WString::Unmanaged(L"Vertical Antialias");
	}

	::vl::WString __vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings::Yes()
	{
		return ::vl::WString::Unmanaged(L"Yes");
	}

	//-------------------------------------------------------------------

	__vwsnc5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorDialogControl* __vwsnctor___vwsn_this_, ::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Green();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::ColorDialogControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorDialogControl* __vwsnctor___vwsn_this_, ::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Blue();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::ColorDialogControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorDialogControl* __vwsnctor___vwsn_this_, ::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsn_this_(__vwsnctor___vwsn_this_)
		, __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->Color();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::ColorDialogControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func<void()>(this, &__vwsnc7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(__vwsn_bind_cache_0)->GetValue();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->self; } catch(...){ return static_cast<::gaclib_controls::ColorDialogControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->ValueChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

	//-------------------------------------------------------------------

	__vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::ColorDialogControlConstructor* __vwsnctorthis_0)
		:__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0))
	{
		this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr);
		this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_0_1 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_handler_0_2 = ::vl::Ptr<::vl::reflection::description::IEventHandler>();
		this->__vwsn_bind_opened_ = false;
		this->__vwsn_bind_closed_ = false;
	}

	void __vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_()
	{
		auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(__vwsn_bind_cache_0)->ReadColor();
		::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_));
	}

	void __vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0()
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_1()
	{
		this->__vwsn_bind_activator_();
	}

	void __vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_2()
	{
		this->__vwsn_bind_activator_();
	}

	bool __vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Open()
	{
		if ((! __vwsn_bind_opened_))
		{
			(__vwsn_bind_opened_ = true);
			(__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->self; } catch(...){ return static_cast<::gaclib_controls::ColorDialogControl*>(nullptr); } }());
			(__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->colorRed)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_0_1 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->colorGreen)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_1)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			(__vwsn_bind_handler_0_2 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->colorBlue)->ValueChanged, ::vl::Func<void()>(this, &__vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_2)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }());
			return true;
		}
		return false;
	}

	bool __vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Update()
	{
		if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_)))
		{
			this->__vwsn_bind_activator_();
			return true;
		}
		return false;
	}

	bool __vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription::Close()
	{
		if ((! __vwsn_bind_closed_))
		{
			(__vwsn_bind_closed_ = true);
			if (static_cast<bool>(__vwsn_bind_handler_0_0))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->colorRed)->ValueChanged, __vwsn_bind_handler_0_0);
				(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_0_1))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->colorGreen)->ValueChanged, __vwsn_bind_handler_0_1);
				(__vwsn_bind_handler_0_1 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			if (static_cast<bool>(__vwsn_bind_handler_0_2))
			{
				::vl::__vwsn::EventDetach(::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->colorBlue)->ValueChanged, __vwsn_bind_handler_0_2);
				(__vwsn_bind_handler_0_2 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			}
			(__vwsn_bind_cache_0 = static_cast<::gaclib_controls::ColorDialogControl*>(nullptr));
			(__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_0_1 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			(__vwsn_bind_handler_0_2 = ::vl::Ptr<::vl::reflection::description::IEventHandler>());
			return true;
		}
		return false;
	}

}

/***********************************************************************
Class (::gaclib_controls::ColorComponentControlConstructor)
***********************************************************************/

namespace gaclib_controls
{
	void ColorComponentControlConstructor::__vwsn_gaclib_controls_ColorComponentControl_Initialize(::gaclib_controls::ColorComponentControl* __vwsn_this_)
	{
		(this->self = __vwsn_this_);
		(this->__vwsn_precompile_0 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetCellPadding(static_cast<::vl::vint>(5));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowsAndColumns(static_cast<::vl::vint>(1), static_cast<::vl::vint>(2));
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Absolute; __vwsn_temp__.absolute = static_cast<::vl::vint>(48); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_1 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->textBox = new ::vl::presentation::controls::GuiSinglelineTextBox(::vl::presentation::theme::ThemeName::SinglelineTextBox));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"textBox"), ::vl::__vwsn::Box(this->textBox));
		}
		(this->__vwsn_precompile_2 = ::vl::__vwsn::This(this->textBox)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->textBox)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_1));
		}
		(this->__vwsn_precompile_3 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->tracker = new ::vl::presentation::controls::GuiScroll(::vl::presentation::theme::ThemeName::HTracker));
			::vl::__vwsn::This(this->tracker)->SetPageSize(static_cast<::vl::vint>(0));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"tracker"), ::vl::__vwsn::Box(this->tracker));
		}
		{
			::vl::__vwsn::This(this->tracker)->SetBigMove(static_cast<::vl::vint>(16));
		}
		{
			::vl::__vwsn::This(this->tracker)->SetSmallMove(static_cast<::vl::vint>(1));
		}
		{
			::vl::__vwsn::This(this->tracker)->SetPageSize(static_cast<::vl::vint>(1));
		}
		{
			::vl::__vwsn::This(this->tracker)->SetTotalSize(static_cast<::vl::vint>(256));
		}
		(this->__vwsn_precompile_4 = ::vl::__vwsn::This(this->tracker)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->tracker)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_3));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_0));
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf1_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf2_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->textBox)->TextChanged, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc3_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf4_GuiFakeDialogServiceUI_gaclib_controls_ColorComponentControlConstructor___vwsn_gaclib_controls_ColorComponentControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
	}

	ColorComponentControlConstructor::ColorComponentControlConstructor()
		: self(static_cast<::gaclib_controls::ColorComponentControl*>(nullptr))
		, textBox(static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr))
		, tracker(static_cast<::vl::presentation::controls::GuiScroll*>(nullptr))
		, __vwsn_precompile_0(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_1(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_2(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_3(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_4(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
	{
	}

/***********************************************************************
Class (::gaclib_controls::ColorComponentControl)
***********************************************************************/

	::vl::vint ColorComponentControl::GetValue()
	{
		return this->__vwsn_prop_Value;
	}
	void ColorComponentControl::SetValue(::vl::vint __vwsn_value_)
	{
		if ((this->__vwsn_prop_Value != __vwsn_value_))
		{
			(this->__vwsn_prop_Value = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->ValueChanged)();
		}
	}

	::vl::WString ColorComponentControl::GetTextBoxAlt()
	{
		return this->__vwsn_prop_TextBoxAlt;
	}
	void ColorComponentControl::SetTextBoxAlt(const ::vl::WString& __vwsn_value_)
	{
		if ((this->__vwsn_prop_TextBoxAlt != __vwsn_value_))
		{
			(this->__vwsn_prop_TextBoxAlt = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->TextBoxAltChanged)();
		}
	}

	ColorComponentControl::ColorComponentControl()
		: ::vl::presentation::controls::GuiCustomControl(::vl::presentation::theme::ThemeName::CustomControl)
		, __vwsn_prop_Value(static_cast<::vl::vint>(0))
		, __vwsn_prop_TextBoxAlt(::vl::WString::Unmanaged(L""))
	{
		auto __vwsn_resource_ = ::vl::__vwsn::This(::vl::presentation::GetResourceManager())->GetResourceFromClassName(::vl::WString::Unmanaged(L"gaclib_controls::ColorComponentControl"));
		auto __vwsn_resolver_ = ::vl::Ptr<::vl::presentation::GuiResourcePathResolver>(new ::vl::presentation::GuiResourcePathResolver(__vwsn_resource_, ::vl::__vwsn::This(__vwsn_resource_.Obj())->GetWorkingDirectory()));
		::vl::__vwsn::This(this)->SetResourceResolver(__vwsn_resolver_);
		::vl::__vwsn::This(this)->__vwsn_gaclib_controls_ColorComponentControl_Initialize(this);
	}

	ColorComponentControl::~ColorComponentControl()
	{
		this->FinalizeInstanceRecursively(static_cast<::vl::presentation::controls::GuiCustomControl*>(this));
	}

/***********************************************************************
Class (::gaclib_controls::ColorDialogControlConstructor)
***********************************************************************/

	void ColorDialogControlConstructor::__vwsn_gaclib_controls_ColorDialogControl_Initialize(::gaclib_controls::ColorDialogControl* __vwsn_this_)
	{
		(this->self = __vwsn_this_);
		(this->ViewModel = ::vl::__vwsn::This(__vwsn_this_)->GetViewModel());
		(this->__vwsn_precompile_0 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetCellPadding(static_cast<::vl::vint>(5));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowsAndColumns(static_cast<::vl::vint>(4), static_cast<::vl::vint>(2));
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(3), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_1 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_2 = new ::vl::presentation::controls::GuiLabel(::vl::presentation::theme::ThemeName::Label));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_2)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_1));
		}
		(this->__vwsn_precompile_3 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_4 = new ::vl::presentation::controls::GuiLabel(::vl::presentation::theme::ThemeName::Label));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_4)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_3));
		}
		(this->__vwsn_precompile_5 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetSite(static_cast<::vl::vint>(2), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_6 = new ::vl::presentation::controls::GuiLabel(::vl::presentation::theme::ThemeName::Label));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_6)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_5));
		}
		(this->__vwsn_precompile_7 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->SetSite(static_cast<::vl::vint>(3), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_8 = new ::vl::presentation::controls::GuiLabel(::vl::presentation::theme::ThemeName::Label));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_8)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_7));
		}
		(this->__vwsn_precompile_9 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->colorRed = new ::gaclib_controls::ColorComponentControl());
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"colorRed"), ::vl::__vwsn::Box(this->colorRed));
		{
			::vl::__vwsn::This(this->colorRed)->SetTextBoxAlt(::vl::WString::Unmanaged(L"R"));
		}
		(this->__vwsn_precompile_10 = ::vl::__vwsn::This(this->colorRed)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_10)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->colorRed)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_9));
		}
		(this->__vwsn_precompile_11 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_11)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->colorGreen = new ::gaclib_controls::ColorComponentControl());
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"colorGreen"), ::vl::__vwsn::Box(this->colorGreen));
		{
			::vl::__vwsn::This(this->colorGreen)->SetTextBoxAlt(::vl::WString::Unmanaged(L"G"));
		}
		(this->__vwsn_precompile_12 = ::vl::__vwsn::This(this->colorGreen)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_12)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_11)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->colorGreen)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_11));
		}
		(this->__vwsn_precompile_13 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_13)->SetSite(static_cast<::vl::vint>(2), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->colorBlue = new ::gaclib_controls::ColorComponentControl());
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"colorBlue"), ::vl::__vwsn::Box(this->colorBlue));
		{
			::vl::__vwsn::This(this->colorBlue)->SetTextBoxAlt(::vl::WString::Unmanaged(L"B"));
		}
		(this->__vwsn_precompile_14 = ::vl::__vwsn::This(this->colorBlue)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_13)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->colorBlue)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_13));
		}
		(this->__vwsn_precompile_15 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_15)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(256); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_15)->SetSite(static_cast<::vl::vint>(3), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->__vwsn_precompile_16 = ::vl::Ptr<::vl::presentation::elements::GuiSolidBackgroundElement>(::vl::reflection::description::Element_Constructor<::vl::presentation::elements::GuiSolidBackgroundElement>()));
		{
			::vl::__vwsn::This(this->__vwsn_precompile_15)->SetOwnedElement(::vl::Ptr<::vl::presentation::elements::IGuiGraphicsElement>(this->__vwsn_precompile_16));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_15));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_0));
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc4_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc5_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc6_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc7_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			::vl::__vwsn::This(this->colorRed)->SetValue(static_cast<::vl::vint>(::vl::__vwsn::This(this->ViewModel.Obj())->GetColor().r));
		}
		{
			::vl::__vwsn::This(this->colorGreen)->SetValue(static_cast<::vl::vint>(::vl::__vwsn::This(this->ViewModel.Obj())->GetColor().g));
		}
		{
			::vl::__vwsn::This(this->colorBlue)->SetValue(static_cast<::vl::vint>(::vl::__vwsn::This(this->ViewModel.Obj())->GetColor().b));
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc8_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc9_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc10_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogControlConstructor___vwsn_gaclib_controls_ColorDialogControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
	}

	ColorDialogControlConstructor::ColorDialogControlConstructor()
		: self(static_cast<::gaclib_controls::ColorDialogControl*>(nullptr))
		, ViewModel(::vl::Ptr<::vl::presentation::IColorDialogViewModel>())
		, colorRed(static_cast<::gaclib_controls::ColorComponentControl*>(nullptr))
		, colorGreen(static_cast<::gaclib_controls::ColorComponentControl*>(nullptr))
		, colorBlue(static_cast<::gaclib_controls::ColorComponentControl*>(nullptr))
		, __vwsn_precompile_0(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_1(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_2(static_cast<::vl::presentation::controls::GuiLabel*>(nullptr))
		, __vwsn_precompile_3(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_4(static_cast<::vl::presentation::controls::GuiLabel*>(nullptr))
		, __vwsn_precompile_5(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_6(static_cast<::vl::presentation::controls::GuiLabel*>(nullptr))
		, __vwsn_precompile_7(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_8(static_cast<::vl::presentation::controls::GuiLabel*>(nullptr))
		, __vwsn_precompile_9(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_10(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_11(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_12(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_13(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_14(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_15(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_16(::vl::Ptr<::vl::presentation::elements::GuiSolidBackgroundElement>())
	{
	}

/***********************************************************************
Class (::gaclib_controls::ColorDialogControl)
***********************************************************************/

	::vl::presentation::Color ColorDialogControl::GetValue()
	{
		return this->__vwsn_prop_Value;
	}
	void ColorDialogControl::SetValue(::vl::presentation::Color __vwsn_value_)
	{
		if ((this->__vwsn_prop_Value != __vwsn_value_))
		{
			(this->__vwsn_prop_Value = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->ValueChanged)();
		}
	}

	::vl::presentation::Color ColorDialogControl::ReadColor()
	{
		return [&](){ ::vl::presentation::Color __vwsn_temp__; __vwsn_temp__.r = static_cast<::vl::vuint8_t>(::vl::__vwsn::This(this->colorRed)->GetValue()); __vwsn_temp__.g = static_cast<::vl::vuint8_t>(::vl::__vwsn::This(this->colorGreen)->GetValue()); __vwsn_temp__.b = static_cast<::vl::vuint8_t>(::vl::__vwsn::This(this->colorBlue)->GetValue()); return __vwsn_temp__; }();
	}

	::vl::Ptr<::gaclib_controls::IDialogStringsStrings> ColorDialogControl::GetStrings()
	{
		return this->__vwsn_prop_Strings;
	}
	void ColorDialogControl::SetStrings(::vl::Ptr<::gaclib_controls::IDialogStringsStrings> __vwsn_value_)
	{
		if ((this->__vwsn_prop_Strings.Obj() != __vwsn_value_.Obj()))
		{
			(this->__vwsn_prop_Strings = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->StringsChanged)();
		}
	}

	::vl::Ptr<::vl::presentation::IColorDialogViewModel> ColorDialogControl::GetViewModel()
	{
		return this->__vwsn_parameter_ViewModel;
	}

	ColorDialogControl::ColorDialogControl(::vl::Ptr<::vl::presentation::IColorDialogViewModel> __vwsn_ctor_parameter_ViewModel)
		: ::vl::presentation::controls::GuiCustomControl(::vl::presentation::theme::ThemeName::CustomControl)
		, __vwsn_prop_Value(::vl::__vwsn::Parse<::vl::presentation::Color>(::vl::WString::Unmanaged(L"#FFFFFF")))
		, __vwsn_prop_Strings(::gaclib_controls::DialogStrings::Get(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US"))))
		, __vwsn_parameter_ViewModel(::vl::Ptr<::vl::presentation::IColorDialogViewModel>())
	{
		(this->__vwsn_parameter_ViewModel = __vwsn_ctor_parameter_ViewModel);
		auto __vwsn_resource_ = ::vl::__vwsn::This(::vl::presentation::GetResourceManager())->GetResourceFromClassName(::vl::WString::Unmanaged(L"gaclib_controls::ColorDialogControl"));
		auto __vwsn_resolver_ = ::vl::Ptr<::vl::presentation::GuiResourcePathResolver>(new ::vl::presentation::GuiResourcePathResolver(__vwsn_resource_, ::vl::__vwsn::This(__vwsn_resource_.Obj())->GetWorkingDirectory()));
		::vl::__vwsn::This(this)->SetResourceResolver(__vwsn_resolver_);
		::vl::__vwsn::This(this)->__vwsn_gaclib_controls_ColorDialogControl_Initialize(this);
	}

	ColorDialogControl::~ColorDialogControl()
	{
		this->FinalizeInstanceRecursively(static_cast<::vl::presentation::controls::GuiCustomControl*>(this));
	}

/***********************************************************************
Class (::gaclib_controls::ColorDialogWindowConstructor)
***********************************************************************/

	void ColorDialogWindowConstructor::__vwsn_gaclib_controls_ColorDialogWindow_Initialize(::gaclib_controls::ColorDialogWindow* __vwsn_this_)
	{
		(this->self = __vwsn_this_);
		(this->ViewModel = ::vl::__vwsn::This(__vwsn_this_)->GetViewModel());
		{
			::vl::__vwsn::This(this->self)->SetIconVisible(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetMinimizedBox(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetMaximizedBox(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetShowInTaskBar(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetClientSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(240); __vwsn_temp__.y = static_cast<::vl::vint>(120); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_0 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetCellPadding(static_cast<::vl::vint>(10));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(10); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowsAndColumns(static_cast<::vl::vint>(2), static_cast<::vl::vint>(3));
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_1 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(3));
		}
		(this->colorControl = new ::gaclib_controls::ColorDialogControl(this->ViewModel));
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"colorControl"), ::vl::__vwsn::Box(this->colorControl));
		(this->__vwsn_precompile_2 = ::vl::__vwsn::This(this->colorControl)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->colorControl)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_1));
		}
		(this->__vwsn_precompile_3 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_4 = new ::vl::presentation::controls::GuiButton(::vl::presentation::theme::ThemeName::Button));
		}
		(this->__vwsn_precompile_5 = ::vl::__vwsn::This(this->__vwsn_precompile_4)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(80); __vwsn_temp__.y = static_cast<::vl::vint>(24); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->SetAlt(::vl::WString::Unmanaged(L"O"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_4)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_3));
		}
		(this->__vwsn_precompile_6 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_6)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(2), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_7 = new ::vl::presentation::controls::GuiButton(::vl::presentation::theme::ThemeName::Button));
		}
		(this->__vwsn_precompile_8 = ::vl::__vwsn::This(this->__vwsn_precompile_7)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_8)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(80); __vwsn_temp__.y = static_cast<::vl::vint>(24); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_8)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->SetAlt(::vl::WString::Unmanaged(L"C"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_6)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_7)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_6));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_0));
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc11_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->__vwsn_precompile_4)->Clicked, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc12_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf15_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->__vwsn_precompile_7)->Clicked, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc13_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf16_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc14_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf17_GuiFakeDialogServiceUI_gaclib_controls_ColorDialogWindowConstructor___vwsn_gaclib_controls_ColorDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
	}

	ColorDialogWindowConstructor::ColorDialogWindowConstructor()
		: self(static_cast<::gaclib_controls::ColorDialogWindow*>(nullptr))
		, ViewModel(::vl::Ptr<::vl::presentation::IColorDialogViewModel>())
		, colorControl(static_cast<::gaclib_controls::ColorDialogControl*>(nullptr))
		, __vwsn_precompile_0(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_1(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_2(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_3(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_4(static_cast<::vl::presentation::controls::GuiButton*>(nullptr))
		, __vwsn_precompile_5(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_6(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_7(static_cast<::vl::presentation::controls::GuiButton*>(nullptr))
		, __vwsn_precompile_8(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
	{
	}

/***********************************************************************
Class (::gaclib_controls::ColorDialogWindow)
***********************************************************************/

	::vl::Ptr<::gaclib_controls::IDialogStringsStrings> ColorDialogWindow::GetStrings()
	{
		return this->__vwsn_prop_Strings;
	}
	void ColorDialogWindow::SetStrings(::vl::Ptr<::gaclib_controls::IDialogStringsStrings> __vwsn_value_)
	{
		if ((this->__vwsn_prop_Strings.Obj() != __vwsn_value_.Obj()))
		{
			(this->__vwsn_prop_Strings = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->StringsChanged)();
		}
	}

	::vl::Ptr<::vl::presentation::IColorDialogViewModel> ColorDialogWindow::GetViewModel()
	{
		return this->__vwsn_parameter_ViewModel;
	}

	ColorDialogWindow::ColorDialogWindow(::vl::Ptr<::vl::presentation::IColorDialogViewModel> __vwsn_ctor_parameter_ViewModel)
		: ::vl::presentation::controls::GuiWindow(::vl::presentation::theme::ThemeName::Window)
		, __vwsn_prop_Strings(::gaclib_controls::DialogStrings::Get(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US"))))
		, __vwsn_parameter_ViewModel(::vl::Ptr<::vl::presentation::IColorDialogViewModel>())
	{
		(this->__vwsn_parameter_ViewModel = __vwsn_ctor_parameter_ViewModel);
		auto __vwsn_resource_ = ::vl::__vwsn::This(::vl::presentation::GetResourceManager())->GetResourceFromClassName(::vl::WString::Unmanaged(L"gaclib_controls::ColorDialogWindow"));
		auto __vwsn_resolver_ = ::vl::Ptr<::vl::presentation::GuiResourcePathResolver>(new ::vl::presentation::GuiResourcePathResolver(__vwsn_resource_, ::vl::__vwsn::This(__vwsn_resource_.Obj())->GetWorkingDirectory()));
		::vl::__vwsn::This(this)->SetResourceResolver(__vwsn_resolver_);
		::vl::__vwsn::This(this)->__vwsn_gaclib_controls_ColorDialogWindow_Initialize(this);
	}

	ColorDialogWindow::~ColorDialogWindow()
	{
		this->FinalizeInstanceRecursively(static_cast<::vl::presentation::controls::GuiControlHost*>(this));
	}

/***********************************************************************
Class (::gaclib_controls::DialogStrings)
***********************************************************************/

	::vl::Ptr<::gaclib_controls::IDialogStringsStrings> DialogStrings::__vwsn_ls_en_US_BuildStrings(::vl::Locale __vwsn_ls_locale)
	{
		return ::vl::Ptr<::gaclib_controls::IDialogStringsStrings>(new ::vl_workflow_global::__vwsnc58_GuiFakeDialogServiceUI_gaclib_controls_DialogStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IDialogStringsStrings());
	}

	void DialogStrings::Install(::vl::Locale __vwsn_ls_locale, ::vl::Ptr<::gaclib_controls::IDialogStringsStrings> __vwsn_ls_impl)
	{
		if (::vl::__vwsn::This(::vl::__vwsn::This(GLOBAL_NAME __vwsn_ls_DialogStrings.Obj())->GetKeys().Obj())->Contains(::vl::__vwsn::Box(__vwsn_ls_locale)))
		{
			throw ::vl::Exception(((::vl::WString::Unmanaged(L"Localized strings \"gaclib_controls::DialogStrings\" has already registered for locale \"") + ::vl::__vwsn::ToString(__vwsn_ls_locale)) + ::vl::WString::Unmanaged(L"\".")));
		}
		::vl::__vwsn::This(GLOBAL_NAME __vwsn_ls_DialogStrings.Obj())->Set(::vl::__vwsn::Box(__vwsn_ls_locale), ::vl::__vwsn::Box(__vwsn_ls_impl));
	}

	::vl::Ptr<::gaclib_controls::IDialogStringsStrings> DialogStrings::Get(::vl::Locale __vwsn_ls_locale)
	{
		if (::vl::__vwsn::This(::vl::__vwsn::This(GLOBAL_NAME __vwsn_ls_DialogStrings.Obj())->GetKeys().Obj())->Contains(::vl::__vwsn::Box(__vwsn_ls_locale)))
		{
			return ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IDialogStringsStrings>>(::vl::__vwsn::This(GLOBAL_NAME __vwsn_ls_DialogStrings.Obj())->Get(::vl::__vwsn::Box(__vwsn_ls_locale)));
		}
		return ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IDialogStringsStrings>>(::vl::__vwsn::This(GLOBAL_NAME __vwsn_ls_DialogStrings.Obj())->Get(::vl::__vwsn::Box(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US")))));
	}

	DialogStrings::DialogStrings()
	{
	}

/***********************************************************************
Class (::gaclib_controls::FileDialogWindowConstructor)
***********************************************************************/

	void FileDialogWindowConstructor::__vwsn_gaclib_controls_FileDialogWindow_Initialize(::gaclib_controls::FileDialogWindow* __vwsn_this_)
	{
		(this->self = __vwsn_this_);
		(this->ViewModel = ::vl::__vwsn::This(__vwsn_this_)->GetViewModel());
		{
			::vl::__vwsn::This(this->self)->SetIconVisible(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetMinimizedBox(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetMaximizedBox(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetShowInTaskBar(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetClientSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(480); __vwsn_temp__.y = static_cast<::vl::vint>(360); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_0 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetCellPadding(static_cast<::vl::vint>(5));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(5); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowsAndColumns(static_cast<::vl::vint>(2), static_cast<::vl::vint>(3));
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_1 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(3));
		}
		(this->filePickerControl = new ::gaclib_controls::FilePickerControl(this->ViewModel));
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"filePickerControl"), ::vl::__vwsn::Box(this->filePickerControl));
		(this->__vwsn_precompile_2 = ::vl::__vwsn::This(this->filePickerControl)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->filePickerControl)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_1));
		}
		(this->__vwsn_precompile_3 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->buttonOK = new ::vl::presentation::controls::GuiButton(::vl::presentation::theme::ThemeName::Button));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"buttonOK"), ::vl::__vwsn::Box(this->buttonOK));
		}
		(this->__vwsn_precompile_4 = ::vl::__vwsn::This(this->buttonOK)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(80); __vwsn_temp__.y = static_cast<::vl::vint>(24); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->buttonOK)->SetAlt(::vl::WString::Unmanaged(L"O"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->buttonOK)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_3));
		}
		(this->__vwsn_precompile_5 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(2), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_6 = new ::vl::presentation::controls::GuiButton(::vl::presentation::theme::ThemeName::Button));
		}
		(this->__vwsn_precompile_7 = ::vl::__vwsn::This(this->__vwsn_precompile_6)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(80); __vwsn_temp__.y = static_cast<::vl::vint>(24); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_6)->SetAlt(::vl::WString::Unmanaged(L"C"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_6)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_5));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_0));
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf18_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->filePickerControl)->RequestClose, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc15_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf20_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf21_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->buttonOK)->Clicked, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc16_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf22_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf23_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->__vwsn_precompile_6)->Clicked, __vwsn_event_handler_);
		}
		{
			::vl::__vwsn::This(this->self)->SetText(::vl::__vwsn::This(this->ViewModel.Obj())->GetTitle());
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc17_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf24_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindowConstructor___vwsn_gaclib_controls_FileDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
	}

	FileDialogWindowConstructor::FileDialogWindowConstructor()
		: self(static_cast<::gaclib_controls::FileDialogWindow*>(nullptr))
		, ViewModel(::vl::Ptr<::vl::presentation::IFileDialogViewModel>())
		, filePickerControl(static_cast<::gaclib_controls::FilePickerControl*>(nullptr))
		, buttonOK(static_cast<::vl::presentation::controls::GuiButton*>(nullptr))
		, __vwsn_precompile_0(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_1(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_2(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_3(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_4(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_5(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_6(static_cast<::vl::presentation::controls::GuiButton*>(nullptr))
		, __vwsn_precompile_7(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
	{
	}

/***********************************************************************
Class (::gaclib_controls::FileDialogWindow)
***********************************************************************/

	void FileDialogWindow::MakeOpenFileDialog()
	{
		::vl::__vwsn::This(this->buttonOK)->SetText(::vl::__vwsn::This(this->GetStrings().Obj())->FileDialogOpen());
	}

	void FileDialogWindow::MakeSaveFileDialog()
	{
		::vl::__vwsn::This(this->buttonOK)->SetText(::vl::__vwsn::This(this->GetStrings().Obj())->FileDialogSave());
	}

	::vl::Ptr<::gaclib_controls::IDialogStringsStrings> FileDialogWindow::GetStrings()
	{
		return this->__vwsn_prop_Strings;
	}
	void FileDialogWindow::SetStrings(::vl::Ptr<::gaclib_controls::IDialogStringsStrings> __vwsn_value_)
	{
		if ((this->__vwsn_prop_Strings.Obj() != __vwsn_value_.Obj()))
		{
			(this->__vwsn_prop_Strings = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->StringsChanged)();
		}
	}

	::vl::Ptr<::vl::presentation::IFileDialogViewModel> FileDialogWindow::GetViewModel()
	{
		return this->__vwsn_parameter_ViewModel;
	}

	FileDialogWindow::FileDialogWindow(::vl::Ptr<::vl::presentation::IFileDialogViewModel> __vwsn_ctor_parameter_ViewModel)
		: ::vl::presentation::controls::GuiWindow(::vl::presentation::theme::ThemeName::Window)
		, __vwsn_prop_Strings(::gaclib_controls::DialogStrings::Get(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US"))))
		, __vwsn_parameter_ViewModel(::vl::Ptr<::vl::presentation::IFileDialogViewModel>())
	{
		(this->__vwsn_parameter_ViewModel = __vwsn_ctor_parameter_ViewModel);
		auto __vwsn_resource_ = ::vl::__vwsn::This(::vl::presentation::GetResourceManager())->GetResourceFromClassName(::vl::WString::Unmanaged(L"gaclib_controls::FileDialogWindow"));
		auto __vwsn_resolver_ = ::vl::Ptr<::vl::presentation::GuiResourcePathResolver>(new ::vl::presentation::GuiResourcePathResolver(__vwsn_resource_, ::vl::__vwsn::This(__vwsn_resource_.Obj())->GetWorkingDirectory()));
		::vl::__vwsn::This(this)->SetResourceResolver(__vwsn_resolver_);
		::vl::__vwsn::This(this)->__vwsn_gaclib_controls_FileDialogWindow_Initialize(this);
		this->__vwsn_instance_ctor_();
	}

	void FileDialogWindow::__vwsn_instance_ctor_()
	{
		::vl::__vwsn::This(::vl::presentation::controls::GetApplication())->InvokeInMainThread(static_cast<::vl::presentation::controls::GuiControlHost*>(this->self), vl::Func(::vl_workflow_global::__vwsnf25_GuiFakeDialogServiceUI_gaclib_controls_FileDialogWindow___vwsn_instance_ctor__(this)));
	}

	FileDialogWindow::~FileDialogWindow()
	{
		this->FinalizeInstanceRecursively(static_cast<::vl::presentation::controls::GuiControlHost*>(this));
	}

/***********************************************************************
Class (::gaclib_controls::FilePickerControlConstructor)
***********************************************************************/

	void FilePickerControlConstructor::__vwsn_gaclib_controls_FilePickerControl_Initialize(::gaclib_controls::FilePickerControl* __vwsn_this_)
	{
		(this->self = __vwsn_this_);
		(this->ViewModel = ::vl::__vwsn::This(__vwsn_this_)->GetViewModel());
		(this->__vwsn_precompile_24 = ::vl::__vwsn::This(this->self)->GetViewModel());
		(this->__vwsn_precompile_0 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetCellPadding(static_cast<::vl::vint>(5));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowsAndColumns(static_cast<::vl::vint>(3), static_cast<::vl::vint>(1));
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_1 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_2 = new ::vl::presentation::controls::GuiLabel(::vl::presentation::theme::ThemeName::Label));
		}
		(this->__vwsn_precompile_3 = ::vl::__vwsn::This(this->__vwsn_precompile_2)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_2)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_1));
		}
		(this->__vwsn_precompile_4 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->__vwsn_precompile_5 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetCellPadding(static_cast<::vl::vint>(5));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetRowsAndColumns(static_cast<::vl::vint>(1), static_cast<::vl::vint>(2));
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Absolute; __vwsn_temp__.absolute = static_cast<::vl::vint>(192); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_6 = new ::vl::presentation::compositions::GuiColumnSplitterComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_6)->SetColumnsToTheLeft(static_cast<::vl::vint>(1));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_6));
		}
		(this->__vwsn_precompile_7 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->treeView = new ::vl::presentation::controls::GuiBindableTreeView(::vl::presentation::theme::ThemeName::TreeView));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"treeView"), ::vl::__vwsn::Box(this->treeView));
		}
		{
			::vl::__vwsn::This(this->treeView)->SetChildrenProperty(vl::Func(::vl_workflow_global::__vwsnf26_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
		}
		{
			::vl::__vwsn::This(this->treeView)->SetHorizontalAlwaysVisible(false);
		}
		{
			::vl::__vwsn::This(this->treeView)->SetVerticalAlwaysVisible(false);
		}
		{
			::vl::__vwsn::This(this->treeView)->SetTextProperty(vl::Func(::vl_workflow_global::__vwsnf27_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
		}
		(this->__vwsn_precompile_8 = ::vl::__vwsn::This(this->treeView)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_8)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->treeView)->SetAlt(::vl::WString::Unmanaged(L"D"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->treeView)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_7));
		}
		(this->__vwsn_precompile_9 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->dataGrid = new ::vl::presentation::controls::GuiBindableDataGrid(::vl::presentation::theme::ThemeName::ListView));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"dataGrid"), ::vl::__vwsn::Box(this->dataGrid));
		}
		(this->__vwsn_precompile_12 = ::vl::__vwsn::This(this->dataGrid)->GetFocusableComposition());
		{
			::vl::__vwsn::This(this->dataGrid)->SetView(::vl::presentation::controls::ListViewView::List);
		}
		{
			::vl::__vwsn::This(this->dataGrid)->SetHorizontalAlwaysVisible(false);
		}
		{
			::vl::__vwsn::This(this->dataGrid)->SetVerticalAlwaysVisible(false);
		}
		(this->__vwsn_precompile_11 = ::vl::__vwsn::This(this->dataGrid)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_11)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->dataGrid)->SetAlt(::vl::WString::Unmanaged(L"F"));
		}
		(this->__vwsn_precompile_10 = ::vl::Ptr<::vl::presentation::controls::list::DataColumn>(new ::vl::presentation::controls::list::DataColumn()));
		{
			::vl::__vwsn::This(this->__vwsn_precompile_10.Obj())->SetTextProperty(vl::Func(::vl_workflow_global::__vwsnf28_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
		}
		{
			auto __vwsn_collection_ = ::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueList>(::vl::__vwsn::This(this->dataGrid)->GetColumns());
			::vl::__vwsn::This(__vwsn_collection_.Obj())->Add(::vl::__vwsn::Box(this->__vwsn_precompile_10));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->dataGrid)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_9));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_5));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_4));
		}
		(this->__vwsn_precompile_13 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_13)->SetSite(static_cast<::vl::vint>(2), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->__vwsn_precompile_14 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetCellPadding(static_cast<::vl::vint>(5));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetRowsAndColumns(static_cast<::vl::vint>(1), static_cast<::vl::vint>(3));
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetColumnOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Absolute; __vwsn_temp__.absolute = static_cast<::vl::vint>(120); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_15 = new ::vl::presentation::compositions::GuiColumnSplitterComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_15)->SetColumnsToTheLeft(static_cast<::vl::vint>(2));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_15));
		}
		(this->__vwsn_precompile_16 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_16)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_17 = new ::vl::presentation::controls::GuiLabel(::vl::presentation::theme::ThemeName::Label));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_16)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_17)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_16));
		}
		(this->__vwsn_precompile_18 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_18)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->textBox = new ::vl::presentation::controls::GuiSinglelineTextBox(::vl::presentation::theme::ThemeName::SinglelineTextBox));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"textBox"), ::vl::__vwsn::Box(this->textBox));
		}
		(this->__vwsn_precompile_20 = ::vl::__vwsn::This(this->textBox)->GetFocusableComposition());
		(this->__vwsn_precompile_19 = ::vl::__vwsn::This(this->textBox)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_19)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->textBox)->SetAlt(::vl::WString::Unmanaged(L"S"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_18)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->textBox)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_18));
		}
		(this->__vwsn_precompile_21 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_21)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(2), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_22 = new ::vl::presentation::controls::GuiBindableTextList(::vl::presentation::theme::ThemeName::TextList));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_22)->SetHorizontalAlwaysVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_22)->SetVerticalAlwaysVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_22)->SetTextProperty(vl::Func(::vl_workflow_global::__vwsnf29_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
		}
		{
			(this->comboBox = new ::vl::presentation::controls::GuiComboBoxListControl(::vl::presentation::theme::ThemeName::ComboBox, static_cast<::vl::presentation::controls::GuiSelectableListControl*>(this->__vwsn_precompile_22)));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"comboBox"), ::vl::__vwsn::Box(this->comboBox));
		}
		(this->__vwsn_precompile_23 = ::vl::__vwsn::This(this->comboBox)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_23)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->comboBox)->SetAlt(::vl::WString::Unmanaged(L"E"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_21)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->comboBox)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_21));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_13)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_14));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_13));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_0));
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc18_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf30_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			::vl::__vwsn::This(this->treeView)->SetImageProperty(vl::Func(::vl_workflow_global::__vwsno31_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
		}
		{
			::vl::__vwsn::This(this->dataGrid)->SetMultiSelect(::vl::__vwsn::This(this->ViewModel.Obj())->GetEnabledMultipleSelection());
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc19_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf32_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf33_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->__vwsn_precompile_12)->GetEventReceiver()->keyUp, __vwsn_event_handler_);
		}
		{
			::vl::__vwsn::This(this->dataGrid)->SetSmallImageProperty(vl::Func(::vl_workflow_global::__vwsno34_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf35_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->dataGrid)->SelectionChanged, __vwsn_event_handler_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf36_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->dataGrid)->ItemLeftButtonDoubleClick, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc20_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf38_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf39_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->__vwsn_precompile_20)->GetEventReceiver()->keyUp, __vwsn_event_handler_);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_22)->SetItemSource(::vl::Ptr<::vl::reflection::description::IValueEnumerable>(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueReadonlyList>(::vl::__vwsn::This(this->ViewModel.Obj())->GetFilters())));
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc21_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf40_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc22_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf41_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf42_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->__vwsn_precompile_24.Obj())->SelectedFolderChanged, __vwsn_event_handler_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf43_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->__vwsn_precompile_24.Obj())->IsLoadingFilesChanged, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc23_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf44_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControlConstructor___vwsn_gaclib_controls_FilePickerControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
	}

	FilePickerControlConstructor::FilePickerControlConstructor()
		: self(static_cast<::gaclib_controls::FilePickerControl*>(nullptr))
		, ViewModel(::vl::Ptr<::vl::presentation::IFileDialogViewModel>())
		, textBox(static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr))
		, treeView(static_cast<::vl::presentation::controls::GuiBindableTreeView*>(nullptr))
		, dataGrid(static_cast<::vl::presentation::controls::GuiBindableDataGrid*>(nullptr))
		, comboBox(static_cast<::vl::presentation::controls::GuiComboBoxListControl*>(nullptr))
		, __vwsn_precompile_0(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_1(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_2(static_cast<::vl::presentation::controls::GuiLabel*>(nullptr))
		, __vwsn_precompile_3(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_4(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_5(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_6(static_cast<::vl::presentation::compositions::GuiColumnSplitterComposition*>(nullptr))
		, __vwsn_precompile_7(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_8(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_9(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_10(::vl::Ptr<::vl::presentation::controls::list::DataColumn>())
		, __vwsn_precompile_11(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_12(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(nullptr))
		, __vwsn_precompile_13(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_14(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_15(static_cast<::vl::presentation::compositions::GuiColumnSplitterComposition*>(nullptr))
		, __vwsn_precompile_16(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_17(static_cast<::vl::presentation::controls::GuiLabel*>(nullptr))
		, __vwsn_precompile_18(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_19(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_20(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(nullptr))
		, __vwsn_precompile_21(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_22(static_cast<::vl::presentation::controls::GuiBindableTextList*>(nullptr))
		, __vwsn_precompile_23(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_24(::vl::Ptr<::vl::presentation::IFileDialogViewModel>())
	{
	}

/***********************************************************************
Class (::gaclib_controls::FilePickerControl)
***********************************************************************/

	::vl::collections::LazyList<::vl::Ptr<::vl::presentation::IFileDialogFile>> FilePickerControl::GetSelectedFiles()
	{
		return ::vl::reflection::description::GetLazyList<::vl::Ptr<::vl::presentation::IFileDialogFile>>(::vl::reflection::description::EnumerableCoroutine::Create(vl::Func(::vl_workflow_global::__vwsnf45_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_GetSelectedFiles_(this))));
	}

	::vl::collections::LazyList<::vl::WString> FilePickerControl::GetSelection()
	{
		return ::vl::__vwsn::This(this->GetViewModel().Obj())->ParseDisplayString(::vl::__vwsn::This(this->textBox)->GetText());
	}

	void FilePickerControl::LocateSelectedFolderInTreeView()
	{
		auto fragments = ::vl::reflection::description::IValueList::Create();
		auto currentFolder = ::vl::__vwsn::This(this->GetViewModel().Obj())->GetSelectedFolder();
		if ((! static_cast<bool>(currentFolder)))
		{
			return;
		}
		while ((static_cast<bool>(currentFolder) && (::vl::__vwsn::This(currentFolder.Obj())->GetType() == ::vl::presentation::FileDialogFolderType::Folder)))
		{
			::vl::__vwsn::This(fragments.Obj())->Add(::vl::__vwsn::Box(currentFolder));
			(currentFolder = ::vl::__vwsn::This(currentFolder.Obj())->GetParent());
		}
		auto currentNode = ::vl::__vwsn::This(::vl::__vwsn::This(this->treeView)->GetNodeRootProvider())->GetRootNode();
		{
			auto __vwsn_for_enumerable_fragment = ::vl::reflection::description::Sys::ReverseEnumerable(::vl::Ptr<::vl::reflection::description::IValueEnumerable>(fragments));
			auto __vwsn_for_enumerator_fragment = ::vl::__vwsn::This(__vwsn_for_enumerable_fragment.Obj())->CreateEnumerator();
			while (::vl::__vwsn::This(__vwsn_for_enumerator_fragment.Obj())->Next())
			{
				auto fragment = ::vl::__vwsn::Unbox<::vl::Ptr<::vl::presentation::IFileDialogFolder>>(::vl::__vwsn::This(__vwsn_for_enumerator_fragment.Obj())->GetCurrent());
				{
					::vl::__vwsn::This(currentNode.Obj())->SetExpanding(true);
					(currentNode = ::vl::__vwsn::This(currentNode.Obj())->GetChild(::vl::__vwsn::This(fragment.Obj())->GetIndex()));
					if ((! static_cast<bool>(currentNode)))
					{
						return;
					}
				}
			}
		}
		auto index = ::vl::__vwsn::This(::vl::__vwsn::This(this->treeView)->GetNodeItemView())->CalculateNodeVisibilityIndex(::vl::__vwsn::Ensure(static_cast<::vl::presentation::controls::tree::INodeProvider*>(currentNode.Obj())));
		::vl::__vwsn::This(this->treeView)->EnsureItemVisible(index);
		::vl::__vwsn::This(this->treeView)->SelectItemsByClick(index, false, false, true);
	}

	::vl::Ptr<::vl::presentation::controls::list::IDataFilter> FilePickerControl::CreateFileFilter(::vl::Ptr<::vl::presentation::IFileDialogFilter> filter)
	{
		if ((! static_cast<bool>(filter)))
		{
			return ::vl::Ptr<::vl::presentation::controls::list::IDataFilter>();
		}
		else
		{
			return ::vl::Ptr<::vl::presentation::controls::list::IDataFilter>(new ::vl_workflow_global::__vwsnc25_GuiFakeDialogServiceUI_gaclib_controls_FilePickerControl_CreateFileFilter__vl_presentation_controls_list_IDataFilter(filter, this));
		}
	}

	::vl::Ptr<::gaclib_controls::IDialogStringsStrings> FilePickerControl::GetStrings()
	{
		return this->__vwsn_prop_Strings;
	}
	void FilePickerControl::SetStrings(::vl::Ptr<::gaclib_controls::IDialogStringsStrings> __vwsn_value_)
	{
		if ((this->__vwsn_prop_Strings.Obj() != __vwsn_value_.Obj()))
		{
			(this->__vwsn_prop_Strings = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->StringsChanged)();
		}
	}

	::vl::Ptr<::vl::presentation::IFileDialogViewModel> FilePickerControl::GetViewModel()
	{
		return this->__vwsn_parameter_ViewModel;
	}

	FilePickerControl::FilePickerControl(::vl::Ptr<::vl::presentation::IFileDialogViewModel> __vwsn_ctor_parameter_ViewModel)
		: ::vl::presentation::controls::GuiCustomControl(::vl::presentation::theme::ThemeName::CustomControl)
		, imageFolder(::vl::Ptr<::vl::presentation::GuiImageData>())
		, imageFile(::vl::Ptr<::vl::presentation::GuiImageData>())
		, __vwsn_prop_Strings(::gaclib_controls::DialogStrings::Get(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US"))))
		, __vwsn_parameter_ViewModel(::vl::Ptr<::vl::presentation::IFileDialogViewModel>())
	{
		(this->__vwsn_parameter_ViewModel = __vwsn_ctor_parameter_ViewModel);
		auto __vwsn_resource_ = ::vl::__vwsn::This(::vl::presentation::GetResourceManager())->GetResourceFromClassName(::vl::WString::Unmanaged(L"gaclib_controls::FilePickerControl"));
		auto __vwsn_resolver_ = ::vl::Ptr<::vl::presentation::GuiResourcePathResolver>(new ::vl::presentation::GuiResourcePathResolver(__vwsn_resource_, ::vl::__vwsn::This(__vwsn_resource_.Obj())->GetWorkingDirectory()));
		::vl::__vwsn::This(this)->SetResourceResolver(__vwsn_resolver_);
		::vl::__vwsn::This(this)->__vwsn_gaclib_controls_FilePickerControl_Initialize(this);
		this->__vwsn_instance_ctor_();
	}

	void FilePickerControl::__vwsn_instance_ctor_()
	{
		(this->imageFolder = ::vl::__vwsn::Ensure(::vl::__vwsn::SharedPtrCast<::vl::presentation::GuiImageData>(::vl::__vwsn::This(this->self)->ResolveResource(::vl::WString::Unmanaged(L"res"), ::vl::WString::Unmanaged(L"Images/Folder"), true).Obj())));
		(this->imageFile = ::vl::__vwsn::Ensure(::vl::__vwsn::SharedPtrCast<::vl::presentation::GuiImageData>(::vl::__vwsn::This(this->self)->ResolveResource(::vl::WString::Unmanaged(L"res"), ::vl::WString::Unmanaged(L"Images/File"), true).Obj())));
		::vl::__vwsn::This(this->GetViewModel().Obj())->InitLocalizedText(::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetStrings().Obj())->FileDialogTextLoadingFolders(), ::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetStrings().Obj())->FileDialogTextLoadingFiles(), ::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetStrings().Obj())->FileDialogErrorEmptySelection(), ::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetStrings().Obj())->FileDialogErrorFileNotExist(), ::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetStrings().Obj())->FileDialogErrorFileExpected(), ::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetStrings().Obj())->FileDialogErrorFolderNotExist(), ::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetStrings().Obj())->FileDialogErrorMultipleSelectionNotEnabled(), ::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetStrings().Obj())->FileDialogAskCreateFile(), ::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetStrings().Obj())->FileDialogAskOverrideFile());
		::vl::__vwsn::This(this->treeView)->SetItemSource(::vl::__vwsn::Box(::vl::__vwsn::This(this->GetViewModel().Obj())->GetRootFolder()));
		::vl::__vwsn::This(this->dataGrid)->SetItemSource(::vl::Ptr<::vl::reflection::description::IValueEnumerable>(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueObservableList>(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFiles())));
		::vl::__vwsn::This(this->comboBox)->SetSelectedIndex(::vl::__vwsn::This(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueReadonlyList>(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFilters()).Obj())->IndexOf(::vl::__vwsn::Box(::vl::__vwsn::This(this->GetViewModel().Obj())->GetSelectedFilter())));
		::vl::__vwsn::This(this->GetViewModel().Obj())->RefreshFiles();
	}

	FilePickerControl::~FilePickerControl()
	{
		this->FinalizeInstanceRecursively(static_cast<::vl::presentation::controls::GuiCustomControl*>(this));
	}

/***********************************************************************
Class (::gaclib_controls::FontNameControlConstructor)
***********************************************************************/

	void FontNameControlConstructor::__vwsn_gaclib_controls_FontNameControl_Initialize(::gaclib_controls::FontNameControl* __vwsn_this_)
	{
		(this->self = __vwsn_this_);
		(this->ViewModel = ::vl::__vwsn::This(__vwsn_this_)->GetViewModel());
		{
			(this->__vwsn_precompile_0 = new ::vl::presentation::controls::GuiControl(::vl::presentation::theme::ThemeName::GroupBox));
		}
		(this->__vwsn_precompile_6 = ::vl::__vwsn::This(this->__vwsn_precompile_0)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_6)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_1 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetCellPadding(static_cast<::vl::vint>(5));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(5); __vwsn_temp__.top = static_cast<::vl::vint>(5); __vwsn_temp__.right = static_cast<::vl::vint>(5); __vwsn_temp__.bottom = static_cast<::vl::vint>(5); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetRowsAndColumns(static_cast<::vl::vint>(2), static_cast<::vl::vint>(1));
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_2 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->textBox = new ::vl::presentation::controls::GuiSinglelineTextBox(::vl::presentation::theme::ThemeName::SinglelineTextBox));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"textBox"), ::vl::__vwsn::Box(this->textBox));
		}
		(this->__vwsn_precompile_3 = ::vl::__vwsn::This(this->textBox)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->textBox)->SetAlt(::vl::WString::Unmanaged(L"F"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->textBox)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_2));
		}
		(this->__vwsn_precompile_4 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->textList = new ::vl::presentation::controls::GuiBindableTextList(::vl::presentation::theme::ThemeName::TextList));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"textList"), ::vl::__vwsn::Box(this->textList));
		}
		{
			::vl::__vwsn::This(this->textList)->SetHorizontalAlwaysVisible(false);
		}
		{
			::vl::__vwsn::This(this->textList)->SetVerticalAlwaysVisible(false);
		}
		(this->__vwsn_precompile_5 = ::vl::__vwsn::This(this->textList)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->textList)->SetAlt(::vl::WString::Unmanaged(L"N"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->textList)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_4));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->__vwsn_precompile_0)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_1));
		}
		{
			::vl::__vwsn::This(this->self)->AddChild(this->__vwsn_precompile_0);
		}
		{
			::vl::__vwsn::This(this->textBox)->SetEditMode((::vl::__vwsn::This(this->ViewModel.Obj())->GetFontMustExist() ? ::vl::presentation::controls::GuiDocumentEditMode::Selectable : ::vl::presentation::controls::GuiDocumentEditMode::Editable));
		}
		{
			::vl::__vwsn::This(this->textList)->SetItemSource(::vl::Ptr<::vl::reflection::description::IValueEnumerable>(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueReadonlyList>(::vl::__vwsn::This(this->ViewModel.Obj())->GetFontList())));
		}
		{
			::vl::__vwsn::This(this->textList)->SetTextProperty(vl::Func(::vl_workflow_global::__vwsno46_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(this)));
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf47_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->textList)->SelectionChanged, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc26_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf48_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc27_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf49_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc28_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf50_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf51_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->self)->ValueChanged, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc29_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf52_GuiFakeDialogServiceUI_gaclib_controls_FontNameControlConstructor___vwsn_gaclib_controls_FontNameControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
	}

	FontNameControlConstructor::FontNameControlConstructor()
		: self(static_cast<::gaclib_controls::FontNameControl*>(nullptr))
		, ViewModel(::vl::Ptr<::vl::presentation::ICommonFontDialogViewModel>())
		, textBox(static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr))
		, textList(static_cast<::vl::presentation::controls::GuiBindableTextList*>(nullptr))
		, __vwsn_precompile_0(static_cast<::vl::presentation::controls::GuiControl*>(nullptr))
		, __vwsn_precompile_1(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_2(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_3(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_4(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_5(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_6(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
	{
	}

/***********************************************************************
Class (::gaclib_controls::FontNameControl)
***********************************************************************/

	::vl::WString FontNameControl::GetValue()
	{
		return this->__vwsn_prop_Value;
	}
	void FontNameControl::SetValue(const ::vl::WString& __vwsn_value_)
	{
		if ((this->__vwsn_prop_Value != __vwsn_value_))
		{
			(this->__vwsn_prop_Value = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->ValueChanged)();
		}
	}

	bool FontNameControl::GetLegal()
	{
		return this->__vwsn_prop_Legal;
	}
	void FontNameControl::SetLegal(bool __vwsn_value_)
	{
		if ((this->__vwsn_prop_Legal != __vwsn_value_))
		{
			(this->__vwsn_prop_Legal = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->LegalChanged)();
		}
	}

	void FontNameControl::UpdateSelectedIndex()
	{
		auto index = ::vl::__vwsn::This(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueReadonlyList>(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFontList()).Obj())->IndexOf(::vl::__vwsn::Box(this->GetValue()));
		if ((index > (- static_cast<::vl::vint>(1))))
		{
			::vl::__vwsn::This(this->textList)->SelectItemsByClick(index, false, false, true);
			::vl::__vwsn::This(this->textList)->EnsureItemVisible(index);
		}
	}

	void FontNameControl::InitValue(const ::vl::WString& value)
	{
		::vl::__vwsn::This(this->textBox)->SetText(value);
		::vl::__vwsn::This(this->textBox)->SetCaret([&](){ ::vl::presentation::TextPos __vwsn_temp__; __vwsn_temp__.row = static_cast<::vl::vint>(0); __vwsn_temp__.column = static_cast<::vl::vint>(0); return __vwsn_temp__; }(), [&](){ ::vl::presentation::TextPos __vwsn_temp__; __vwsn_temp__.row = static_cast<::vl::vint>(0); __vwsn_temp__.column = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		this->UpdateSelectedIndex();
	}

	::vl::Ptr<::gaclib_controls::IDialogStringsStrings> FontNameControl::GetStrings()
	{
		return this->__vwsn_prop_Strings;
	}
	void FontNameControl::SetStrings(::vl::Ptr<::gaclib_controls::IDialogStringsStrings> __vwsn_value_)
	{
		if ((this->__vwsn_prop_Strings.Obj() != __vwsn_value_.Obj()))
		{
			(this->__vwsn_prop_Strings = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->StringsChanged)();
		}
	}

	::vl::Ptr<::vl::presentation::ICommonFontDialogViewModel> FontNameControl::GetViewModel()
	{
		return this->__vwsn_parameter_ViewModel;
	}

	FontNameControl::FontNameControl(::vl::Ptr<::vl::presentation::ICommonFontDialogViewModel> __vwsn_ctor_parameter_ViewModel)
		: ::vl::presentation::controls::GuiCustomControl(::vl::presentation::theme::ThemeName::CustomControl)
		, __vwsn_prop_Value(::vl::WString::Unmanaged(L""))
		, __vwsn_prop_Legal(false)
		, __vwsn_prop_Strings(::gaclib_controls::DialogStrings::Get(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US"))))
		, __vwsn_parameter_ViewModel(::vl::Ptr<::vl::presentation::ICommonFontDialogViewModel>())
	{
		(this->__vwsn_parameter_ViewModel = __vwsn_ctor_parameter_ViewModel);
		auto __vwsn_resource_ = ::vl::__vwsn::This(::vl::presentation::GetResourceManager())->GetResourceFromClassName(::vl::WString::Unmanaged(L"gaclib_controls::FontNameControl"));
		auto __vwsn_resolver_ = ::vl::Ptr<::vl::presentation::GuiResourcePathResolver>(new ::vl::presentation::GuiResourcePathResolver(__vwsn_resource_, ::vl::__vwsn::This(__vwsn_resource_.Obj())->GetWorkingDirectory()));
		::vl::__vwsn::This(this)->SetResourceResolver(__vwsn_resolver_);
		::vl::__vwsn::This(this)->__vwsn_gaclib_controls_FontNameControl_Initialize(this);
	}

	FontNameControl::~FontNameControl()
	{
		this->FinalizeInstanceRecursively(static_cast<::vl::presentation::controls::GuiCustomControl*>(this));
	}

/***********************************************************************
Class (::gaclib_controls::FontSizeControlConstructor)
***********************************************************************/

	void FontSizeControlConstructor::__vwsn_gaclib_controls_FontSizeControl_Initialize(::gaclib_controls::FontSizeControl* __vwsn_this_)
	{
		(this->self = __vwsn_this_);
		{
			(this->__vwsn_precompile_0 = new ::vl::presentation::controls::GuiControl(::vl::presentation::theme::ThemeName::GroupBox));
		}
		(this->__vwsn_precompile_6 = ::vl::__vwsn::This(this->__vwsn_precompile_0)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_6)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_1 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetCellPadding(static_cast<::vl::vint>(5));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(5); __vwsn_temp__.top = static_cast<::vl::vint>(5); __vwsn_temp__.right = static_cast<::vl::vint>(5); __vwsn_temp__.bottom = static_cast<::vl::vint>(5); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetRowsAndColumns(static_cast<::vl::vint>(2), static_cast<::vl::vint>(1));
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_2 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->textBox = new ::vl::presentation::controls::GuiSinglelineTextBox(::vl::presentation::theme::ThemeName::SinglelineTextBox));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"textBox"), ::vl::__vwsn::Box(this->textBox));
		}
		(this->__vwsn_precompile_3 = ::vl::__vwsn::This(this->textBox)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->textBox)->SetAlt(::vl::WString::Unmanaged(L"S"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->textBox)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_2));
		}
		(this->__vwsn_precompile_4 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->textList = new ::vl::presentation::controls::GuiBindableTextList(::vl::presentation::theme::ThemeName::TextList));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"textList"), ::vl::__vwsn::Box(this->textList));
		}
		{
			::vl::__vwsn::This(this->textList)->SetHorizontalAlwaysVisible(false);
		}
		{
			::vl::__vwsn::This(this->textList)->SetVerticalAlwaysVisible(false);
		}
		(this->__vwsn_precompile_5 = ::vl::__vwsn::This(this->textList)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->textList)->SetAlt(::vl::WString::Unmanaged(L"L"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->textList)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_4));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->__vwsn_precompile_0)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_1));
		}
		{
			::vl::__vwsn::This(this->self)->AddChild(this->__vwsn_precompile_0);
		}
		{
			::vl::__vwsn::This(this->textList)->SetItemSource(::vl::Ptr<::vl::reflection::description::IValueEnumerable>(::vl::__vwsn::This(this->self)->GetSizeList()));
		}
		{
			::vl::__vwsn::This(this->textList)->SetTextProperty(vl::Func(::vl_workflow_global::__vwsno53_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(this)));
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf54_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->textList)->SelectionChanged, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc30_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf55_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc31_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf56_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc32_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf57_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf58_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->self)->ValueChanged, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc33_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf59_GuiFakeDialogServiceUI_gaclib_controls_FontSizeControlConstructor___vwsn_gaclib_controls_FontSizeControl_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
	}

	FontSizeControlConstructor::FontSizeControlConstructor()
		: self(static_cast<::gaclib_controls::FontSizeControl*>(nullptr))
		, textBox(static_cast<::vl::presentation::controls::GuiSinglelineTextBox*>(nullptr))
		, textList(static_cast<::vl::presentation::controls::GuiBindableTextList*>(nullptr))
		, __vwsn_precompile_0(static_cast<::vl::presentation::controls::GuiControl*>(nullptr))
		, __vwsn_precompile_1(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_2(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_3(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_4(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_5(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_6(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
	{
	}

/***********************************************************************
Class (::gaclib_controls::FontSizeControl)
***********************************************************************/

	::vl::Ptr<::vl::reflection::description::IValueList> FontSizeControl::GetSizeList()
	{
		return this->__vwsn_prop_SizeList;
	}
	void FontSizeControl::SetSizeList(::vl::Ptr<::vl::reflection::description::IValueList> __vwsn_value_)
	{
		(this->__vwsn_prop_SizeList = __vwsn_value_);
	}

	::vl::vint FontSizeControl::GetValue()
	{
		return this->__vwsn_prop_Value;
	}
	void FontSizeControl::SetValue(::vl::vint __vwsn_value_)
	{
		if ((this->__vwsn_prop_Value != __vwsn_value_))
		{
			(this->__vwsn_prop_Value = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->ValueChanged)();
		}
	}

	bool FontSizeControl::GetLegal()
	{
		return this->__vwsn_prop_Legal;
	}
	void FontSizeControl::SetLegal(bool __vwsn_value_)
	{
		if ((this->__vwsn_prop_Legal != __vwsn_value_))
		{
			(this->__vwsn_prop_Legal = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->LegalChanged)();
		}
	}

	void FontSizeControl::UpdateSelectedIndex()
	{
		auto index = ::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetSizeList().Obj())->IndexOf(::vl::__vwsn::Box(this->GetValue()));
		if ((index > (- static_cast<::vl::vint>(1))))
		{
			::vl::__vwsn::This(this->textList)->SelectItemsByClick(index, false, false, true);
			::vl::__vwsn::This(this->textList)->EnsureItemVisible(index);
		}
	}

	void FontSizeControl::InitValue(::vl::vint value)
	{
		::vl::__vwsn::This(this->textBox)->SetText(::vl::__vwsn::ToString(value));
		::vl::__vwsn::This(this->textBox)->SetCaret([&](){ ::vl::presentation::TextPos __vwsn_temp__; __vwsn_temp__.row = static_cast<::vl::vint>(0); __vwsn_temp__.column = static_cast<::vl::vint>(0); return __vwsn_temp__; }(), [&](){ ::vl::presentation::TextPos __vwsn_temp__; __vwsn_temp__.row = static_cast<::vl::vint>(0); __vwsn_temp__.column = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		this->UpdateSelectedIndex();
	}

	::vl::Ptr<::gaclib_controls::IDialogStringsStrings> FontSizeControl::GetStrings()
	{
		return this->__vwsn_prop_Strings;
	}
	void FontSizeControl::SetStrings(::vl::Ptr<::gaclib_controls::IDialogStringsStrings> __vwsn_value_)
	{
		if ((this->__vwsn_prop_Strings.Obj() != __vwsn_value_.Obj()))
		{
			(this->__vwsn_prop_Strings = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->StringsChanged)();
		}
	}

	FontSizeControl::FontSizeControl()
		: ::vl::presentation::controls::GuiCustomControl(::vl::presentation::theme::ThemeName::CustomControl)
		, __vwsn_prop_SizeList((::vl::__vwsn::CreateList().Add(static_cast<::vl::vint>(8)).Add(static_cast<::vl::vint>(9)).Add(static_cast<::vl::vint>(10)).Add(static_cast<::vl::vint>(11)).Add(static_cast<::vl::vint>(12)).Add(static_cast<::vl::vint>(14)).Add(static_cast<::vl::vint>(16)).Add(static_cast<::vl::vint>(18)).Add(static_cast<::vl::vint>(20)).Add(static_cast<::vl::vint>(22)).Add(static_cast<::vl::vint>(24)).Add(static_cast<::vl::vint>(26)).Add(static_cast<::vl::vint>(28)).Add(static_cast<::vl::vint>(36)).Add(static_cast<::vl::vint>(48)).Add(static_cast<::vl::vint>(72))).list)
		, __vwsn_prop_Value(static_cast<::vl::vint>(0))
		, __vwsn_prop_Legal(false)
		, __vwsn_prop_Strings(::gaclib_controls::DialogStrings::Get(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US"))))
	{
		auto __vwsn_resource_ = ::vl::__vwsn::This(::vl::presentation::GetResourceManager())->GetResourceFromClassName(::vl::WString::Unmanaged(L"gaclib_controls::FontSizeControl"));
		auto __vwsn_resolver_ = ::vl::Ptr<::vl::presentation::GuiResourcePathResolver>(new ::vl::presentation::GuiResourcePathResolver(__vwsn_resource_, ::vl::__vwsn::This(__vwsn_resource_.Obj())->GetWorkingDirectory()));
		::vl::__vwsn::This(this)->SetResourceResolver(__vwsn_resolver_);
		::vl::__vwsn::This(this)->__vwsn_gaclib_controls_FontSizeControl_Initialize(this);
	}

	FontSizeControl::~FontSizeControl()
	{
		this->FinalizeInstanceRecursively(static_cast<::vl::presentation::controls::GuiCustomControl*>(this));
	}

/***********************************************************************
Class (::gaclib_controls::FullFontDialogWindowConstructor)
***********************************************************************/

	void FullFontDialogWindowConstructor::__vwsn_gaclib_controls_FullFontDialogWindow_Initialize(::gaclib_controls::FullFontDialogWindow* __vwsn_this_)
	{
		(this->self = __vwsn_this_);
		(this->ViewModel = ::vl::__vwsn::This(__vwsn_this_)->GetViewModel());
		{
			::vl::__vwsn::This(this->self)->SetIconVisible(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetMinimizedBox(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetMaximizedBox(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetShowInTaskBar(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetClientSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(360); __vwsn_temp__.y = static_cast<::vl::vint>(480); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_0 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetCellPadding(static_cast<::vl::vint>(10));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowsAndColumns(static_cast<::vl::vint>(3), static_cast<::vl::vint>(3));
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_1 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(3));
		}
		(this->__vwsn_precompile_2 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetCellPadding(static_cast<::vl::vint>(10));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(10); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetRowsAndColumns(static_cast<::vl::vint>(3), static_cast<::vl::vint>(2));
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetRowOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(0.5); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(0.5); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_3 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(3), static_cast<::vl::vint>(1));
		}
		(this->nameControl = new ::gaclib_controls::FontNameControl(::vl::Ptr<::vl::presentation::ICommonFontDialogViewModel>(this->ViewModel)));
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"nameControl"), ::vl::__vwsn::Box(this->nameControl));
		(this->__vwsn_precompile_4 = ::vl::__vwsn::This(this->nameControl)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->nameControl)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_3));
		}
		(this->__vwsn_precompile_5 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->sizeControl = new ::gaclib_controls::FontSizeControl());
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"sizeControl"), ::vl::__vwsn::Box(this->sizeControl));
		(this->__vwsn_precompile_6 = ::vl::__vwsn::This(this->sizeControl)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_6)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->sizeControl)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_5));
		}
		(this->__vwsn_precompile_7 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_8 = new ::vl::presentation::controls::GuiControl(::vl::presentation::theme::ThemeName::GroupBox));
		}
		(this->__vwsn_precompile_16 = ::vl::__vwsn::This(this->__vwsn_precompile_8)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_16)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_9 = new ::vl::presentation::compositions::GuiStackComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetDirection(::vl::presentation::compositions::GuiStackComposition::Direction::Vertical);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		(this->__vwsn_precompile_10 = new ::vl::presentation::compositions::GuiStackItemComposition());
		{
			(this->checkBold = new ::vl::presentation::controls::GuiSelectableButton(::vl::presentation::theme::ThemeName::CheckBox));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"checkBold"), ::vl::__vwsn::Box(this->checkBold));
		}
		{
			::vl::__vwsn::This(this->checkBold)->SetAlt(::vl::WString::Unmanaged(L"B"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_10)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->checkBold)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_10));
		}
		(this->__vwsn_precompile_11 = new ::vl::presentation::compositions::GuiStackItemComposition());
		{
			(this->checkItalic = new ::vl::presentation::controls::GuiSelectableButton(::vl::presentation::theme::ThemeName::CheckBox));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"checkItalic"), ::vl::__vwsn::Box(this->checkItalic));
		}
		{
			::vl::__vwsn::This(this->checkItalic)->SetAlt(::vl::WString::Unmanaged(L"I"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_11)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->checkItalic)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_11));
		}
		(this->__vwsn_precompile_12 = new ::vl::presentation::compositions::GuiStackItemComposition());
		{
			(this->checkUnderline = new ::vl::presentation::controls::GuiSelectableButton(::vl::presentation::theme::ThemeName::CheckBox));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"checkUnderline"), ::vl::__vwsn::Box(this->checkUnderline));
		}
		{
			::vl::__vwsn::This(this->checkUnderline)->SetAlt(::vl::WString::Unmanaged(L"U"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_12)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->checkUnderline)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_12));
		}
		(this->__vwsn_precompile_13 = new ::vl::presentation::compositions::GuiStackItemComposition());
		{
			(this->checkStrikeline = new ::vl::presentation::controls::GuiSelectableButton(::vl::presentation::theme::ThemeName::CheckBox));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"checkStrikeline"), ::vl::__vwsn::Box(this->checkStrikeline));
		}
		{
			::vl::__vwsn::This(this->checkStrikeline)->SetAlt(::vl::WString::Unmanaged(L"U"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_13)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->checkStrikeline)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_13));
		}
		(this->__vwsn_precompile_14 = new ::vl::presentation::compositions::GuiStackItemComposition());
		{
			(this->checkHAA = new ::vl::presentation::controls::GuiSelectableButton(::vl::presentation::theme::ThemeName::CheckBox));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"checkHAA"), ::vl::__vwsn::Box(this->checkHAA));
		}
		{
			::vl::__vwsn::This(this->checkHAA)->SetAlt(::vl::WString::Unmanaged(L"H"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->checkHAA)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_14));
		}
		(this->__vwsn_precompile_15 = new ::vl::presentation::compositions::GuiStackItemComposition());
		{
			(this->checkVAA = new ::vl::presentation::controls::GuiSelectableButton(::vl::presentation::theme::ThemeName::CheckBox));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"checkVAA"), ::vl::__vwsn::Box(this->checkVAA));
		}
		{
			::vl::__vwsn::This(this->checkVAA)->SetAlt(::vl::WString::Unmanaged(L"V"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_15)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->checkVAA)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_15));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->__vwsn_precompile_8)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_9));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_8)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_7));
		}
		(this->__vwsn_precompile_17 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_17)->SetSite(static_cast<::vl::vint>(2), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_18 = new ::vl::presentation::controls::GuiControl(::vl::presentation::theme::ThemeName::GroupBox));
		}
		(this->__vwsn_precompile_21 = ::vl::__vwsn::This(this->__vwsn_precompile_18)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_21)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		(this->colorBounds = new ::vl::presentation::compositions::GuiBoundsComposition());
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"colorBounds"), ::vl::__vwsn::Box(this->colorBounds));
		{
			::vl::__vwsn::This(this->colorBounds)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.y = static_cast<::vl::vint>(20); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->colorBounds)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(1); __vwsn_temp__.top = static_cast<::vl::vint>(1); __vwsn_temp__.right = static_cast<::vl::vint>(1); __vwsn_temp__.bottom = static_cast<::vl::vint>(1); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_19 = ::vl::Ptr<::vl::presentation::elements::Gui3DBorderElement>(::vl::reflection::description::Element_Constructor<::vl::presentation::elements::Gui3DBorderElement>()));
		{
			::vl::__vwsn::This(this->__vwsn_precompile_19.Obj())->SetColor2(::vl::__vwsn::Parse<::vl::presentation::Color>(::vl::WString::Unmanaged(L"#AAAAAA")));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_19.Obj())->SetColor1(::vl::__vwsn::Parse<::vl::presentation::Color>(::vl::WString::Unmanaged(L"#444444")));
		}
		{
			::vl::__vwsn::This(this->colorBounds)->SetOwnedElement(::vl::Ptr<::vl::presentation::elements::IGuiGraphicsElement>(this->__vwsn_precompile_19));
		}
		(this->__vwsn_precompile_20 = new ::vl::presentation::compositions::GuiBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_20)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(1); __vwsn_temp__.top = static_cast<::vl::vint>(1); __vwsn_temp__.right = static_cast<::vl::vint>(1); __vwsn_temp__.bottom = static_cast<::vl::vint>(1); return __vwsn_temp__; }());
		}
		(this->colorBackground = ::vl::Ptr<::vl::presentation::elements::GuiSolidBackgroundElement>(::vl::reflection::description::Element_Constructor<::vl::presentation::elements::GuiSolidBackgroundElement>()));
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"colorBackground"), ::vl::__vwsn::Box(this->colorBackground));
		{
			::vl::__vwsn::This(this->__vwsn_precompile_20)->SetOwnedElement(::vl::Ptr<::vl::presentation::elements::IGuiGraphicsElement>(this->colorBackground));
		}
		{
			::vl::__vwsn::This(this->colorBounds)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_20));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->__vwsn_precompile_18)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->colorBounds));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_17)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_18)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_17));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_2));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_1));
		}
		(this->__vwsn_precompile_22 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_22)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.y = static_cast<::vl::vint>(48); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_22)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(3));
		}
		{
			(this->__vwsn_precompile_23 = new ::vl::presentation::controls::GuiControl(::vl::presentation::theme::ThemeName::GroupBox));
		}
		(this->__vwsn_precompile_28 = ::vl::__vwsn::This(this->__vwsn_precompile_23)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_28)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_24 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_24)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_24)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_24)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_24)->SetRowsAndColumns(static_cast<::vl::vint>(3), static_cast<::vl::vint>(3));
			::vl::__vwsn::This(this->__vwsn_precompile_24)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_24)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_24)->SetRowOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_24)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_24)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_24)->SetColumnOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_25 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_25)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_26 = new ::vl::presentation::controls::GuiLabel(::vl::presentation::theme::ThemeName::Label));
		}
		(this->__vwsn_precompile_27 = ::vl::__vwsn::This(this->__vwsn_precompile_26)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_27)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_26)->SetText(::vl::WString::Unmanaged(L"ABCxyz"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_25)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_26)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_24)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_25));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->__vwsn_precompile_23)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_24));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_22)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_23)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_22));
		}
		(this->__vwsn_precompile_29 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_29)->SetSite(static_cast<::vl::vint>(2), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_30 = new ::vl::presentation::controls::GuiButton(::vl::presentation::theme::ThemeName::Button));
		}
		(this->__vwsn_precompile_31 = ::vl::__vwsn::This(this->__vwsn_precompile_30)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_31)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(80); __vwsn_temp__.y = static_cast<::vl::vint>(24); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_31)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_30)->SetAlt(::vl::WString::Unmanaged(L"O"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_29)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_30)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_29));
		}
		(this->__vwsn_precompile_32 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_32)->SetSite(static_cast<::vl::vint>(2), static_cast<::vl::vint>(2), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_33 = new ::vl::presentation::controls::GuiButton(::vl::presentation::theme::ThemeName::Button));
		}
		(this->__vwsn_precompile_34 = ::vl::__vwsn::This(this->__vwsn_precompile_33)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_34)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(80); __vwsn_temp__.y = static_cast<::vl::vint>(24); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_34)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_33)->SetAlt(::vl::WString::Unmanaged(L"C"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_32)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_33)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_32));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_0));
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc34_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf60_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc35_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf61_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc36_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf62_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc37_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf63_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc38_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf64_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc39_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf65_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc40_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf66_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			::vl::__vwsn::This(this->colorBackground.Obj())->SetColor(::vl::__vwsn::This(this->ViewModel.Obj())->GetColor());
		}
		{
			::vl::__vwsn::This(this->colorBounds)->SetAssociatedCursor(::vl::__vwsn::This(::vl::__vwsn::This(::vl::presentation::GetCurrentController())->ResourceService())->GetSystemCursor(::vl::presentation::INativeCursor::SystemCursorType::Hand));
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf67_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->colorBounds)->GetEventReceiver()->leftButtonUp, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc41_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf68_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc42_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf69_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc43_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf70_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc44_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf71_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc45_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf72_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf73_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->__vwsn_precompile_30)->Clicked, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc46_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf74_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf75_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->__vwsn_precompile_33)->Clicked, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc47_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf76_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc48_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf77_GuiFakeDialogServiceUI_gaclib_controls_FullFontDialogWindowConstructor___vwsn_gaclib_controls_FullFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
	}

	FullFontDialogWindowConstructor::FullFontDialogWindowConstructor()
		: self(static_cast<::gaclib_controls::FullFontDialogWindow*>(nullptr))
		, ViewModel(::vl::Ptr<::vl::presentation::IFullFontDialogViewModel>())
		, nameControl(static_cast<::gaclib_controls::FontNameControl*>(nullptr))
		, sizeControl(static_cast<::gaclib_controls::FontSizeControl*>(nullptr))
		, checkBold(static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr))
		, checkItalic(static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr))
		, checkUnderline(static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr))
		, checkStrikeline(static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr))
		, checkHAA(static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr))
		, checkVAA(static_cast<::vl::presentation::controls::GuiSelectableButton*>(nullptr))
		, colorBounds(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, colorBackground(::vl::Ptr<::vl::presentation::elements::GuiSolidBackgroundElement>())
		, __vwsn_precompile_0(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_1(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_2(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_3(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_4(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_5(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_6(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_7(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_8(static_cast<::vl::presentation::controls::GuiControl*>(nullptr))
		, __vwsn_precompile_9(static_cast<::vl::presentation::compositions::GuiStackComposition*>(nullptr))
		, __vwsn_precompile_10(static_cast<::vl::presentation::compositions::GuiStackItemComposition*>(nullptr))
		, __vwsn_precompile_11(static_cast<::vl::presentation::compositions::GuiStackItemComposition*>(nullptr))
		, __vwsn_precompile_12(static_cast<::vl::presentation::compositions::GuiStackItemComposition*>(nullptr))
		, __vwsn_precompile_13(static_cast<::vl::presentation::compositions::GuiStackItemComposition*>(nullptr))
		, __vwsn_precompile_14(static_cast<::vl::presentation::compositions::GuiStackItemComposition*>(nullptr))
		, __vwsn_precompile_15(static_cast<::vl::presentation::compositions::GuiStackItemComposition*>(nullptr))
		, __vwsn_precompile_16(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_17(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_18(static_cast<::vl::presentation::controls::GuiControl*>(nullptr))
		, __vwsn_precompile_19(::vl::Ptr<::vl::presentation::elements::Gui3DBorderElement>())
		, __vwsn_precompile_20(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_21(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_22(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_23(static_cast<::vl::presentation::controls::GuiControl*>(nullptr))
		, __vwsn_precompile_24(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_25(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_26(static_cast<::vl::presentation::controls::GuiLabel*>(nullptr))
		, __vwsn_precompile_27(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_28(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_29(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_30(static_cast<::vl::presentation::controls::GuiButton*>(nullptr))
		, __vwsn_precompile_31(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_32(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_33(static_cast<::vl::presentation::controls::GuiButton*>(nullptr))
		, __vwsn_precompile_34(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
	{
	}

/***********************************************************************
Class (::gaclib_controls::FullFontDialogWindow)
***********************************************************************/

	::vl::Ptr<::gaclib_controls::IDialogStringsStrings> FullFontDialogWindow::GetStrings()
	{
		return this->__vwsn_prop_Strings;
	}
	void FullFontDialogWindow::SetStrings(::vl::Ptr<::gaclib_controls::IDialogStringsStrings> __vwsn_value_)
	{
		if ((this->__vwsn_prop_Strings.Obj() != __vwsn_value_.Obj()))
		{
			(this->__vwsn_prop_Strings = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->StringsChanged)();
		}
	}

	::vl::Ptr<::vl::presentation::IFullFontDialogViewModel> FullFontDialogWindow::GetViewModel()
	{
		return this->__vwsn_parameter_ViewModel;
	}

	FullFontDialogWindow::FullFontDialogWindow(::vl::Ptr<::vl::presentation::IFullFontDialogViewModel> __vwsn_ctor_parameter_ViewModel)
		: ::vl::presentation::controls::GuiWindow(::vl::presentation::theme::ThemeName::Window)
		, __vwsn_prop_Strings(::gaclib_controls::DialogStrings::Get(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US"))))
		, __vwsn_parameter_ViewModel(::vl::Ptr<::vl::presentation::IFullFontDialogViewModel>())
	{
		(this->__vwsn_parameter_ViewModel = __vwsn_ctor_parameter_ViewModel);
		auto __vwsn_resource_ = ::vl::__vwsn::This(::vl::presentation::GetResourceManager())->GetResourceFromClassName(::vl::WString::Unmanaged(L"gaclib_controls::FullFontDialogWindow"));
		auto __vwsn_resolver_ = ::vl::Ptr<::vl::presentation::GuiResourcePathResolver>(new ::vl::presentation::GuiResourcePathResolver(__vwsn_resource_, ::vl::__vwsn::This(__vwsn_resource_.Obj())->GetWorkingDirectory()));
		::vl::__vwsn::This(this)->SetResourceResolver(__vwsn_resolver_);
		::vl::__vwsn::This(this)->__vwsn_gaclib_controls_FullFontDialogWindow_Initialize(this);
		this->__vwsn_instance_ctor_();
	}

	void FullFontDialogWindow::__vwsn_instance_ctor_()
	{
		::vl::__vwsn::This(this->nameControl)->InitValue(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFont().fontFamily);
		::vl::__vwsn::This(this->sizeControl)->InitValue(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFont().size);
		::vl::__vwsn::This(this->checkBold)->SetSelected(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFont().bold);
		::vl::__vwsn::This(this->checkItalic)->SetSelected(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFont().italic);
		::vl::__vwsn::This(this->checkUnderline)->SetSelected(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFont().underline);
		::vl::__vwsn::This(this->checkStrikeline)->SetSelected(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFont().strikeline);
		::vl::__vwsn::This(this->checkHAA)->SetSelected(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFont().antialias);
		::vl::__vwsn::This(this->checkVAA)->SetSelected(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFont().verticalAntialias);
	}

	FullFontDialogWindow::~FullFontDialogWindow()
	{
		this->FinalizeInstanceRecursively(static_cast<::vl::presentation::controls::GuiControlHost*>(this));
	}

/***********************************************************************
Class (::gaclib_controls::IDialogStringsStrings)
***********************************************************************/

/***********************************************************************
Class (::gaclib_controls::MessageBoxButtonTemplateConstructor)
***********************************************************************/

	void MessageBoxButtonTemplateConstructor::__vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize(::gaclib_controls::MessageBoxButtonTemplate* __vwsn_this_)
	{
		(this->self = __vwsn_this_);
		(this->Action = ::vl::__vwsn::This(__vwsn_this_)->GetAction());
		{
			::vl::__vwsn::This(this->self)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			(this->buttonControl = new ::vl::presentation::controls::GuiButton(::vl::presentation::theme::ThemeName::Button));
			::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"buttonControl"), ::vl::__vwsn::Box(this->buttonControl));
		}
		(this->__vwsn_precompile_0 = ::vl::__vwsn::This(this->buttonControl)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(80); __vwsn_temp__.y = static_cast<::vl::vint>(24); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->self)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->buttonControl)->GetBoundsComposition()));
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc56_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf87_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			::vl::__vwsn::This(this->buttonControl)->SetAlt(::vl::__vwsn::This(this->self)->GetButtonAlt(::vl::__vwsn::This(this->Action.Obj())->GetButton()));
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf88_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->buttonControl)->Clicked, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc57_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf89_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxButtonTemplateConstructor___vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
	}

	MessageBoxButtonTemplateConstructor::MessageBoxButtonTemplateConstructor()
		: Action(::vl::Ptr<::vl::presentation::IMessageBoxDialogAction>())
		, self(static_cast<::gaclib_controls::MessageBoxButtonTemplate*>(nullptr))
		, buttonControl(static_cast<::vl::presentation::controls::GuiButton*>(nullptr))
		, __vwsn_precompile_0(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
	{
	}

/***********************************************************************
Class (::gaclib_controls::MessageBoxButtonTemplate)
***********************************************************************/

	::vl::presentation::controls::GuiButton* MessageBoxButtonTemplate::GetButtonControl()
	{
		return this->__vwsn_prop_ButtonControl;
	}
	void MessageBoxButtonTemplate::SetButtonControl(::vl::presentation::controls::GuiButton* __vwsn_value_)
	{
		if ((this->__vwsn_prop_ButtonControl != __vwsn_value_))
		{
			(this->__vwsn_prop_ButtonControl = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->ButtonControlChanged)();
		}
	}

	::vl::WString MessageBoxButtonTemplate::GetButtonText(::vl::presentation::INativeDialogService::MessageBoxButtonsOutput button, ::vl::Ptr<::gaclib_controls::IDialogStringsStrings> strings)
	{
		{
			auto __vwsn_switch_0 = button;
			if ((__vwsn_switch_0 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectOK))
			{
				return ::vl::__vwsn::This(strings.Obj())->OK();
			}
			else if ((__vwsn_switch_0 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectCancel))
			{
				return ::vl::__vwsn::This(strings.Obj())->Cancel();
			}
			else if ((__vwsn_switch_0 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectYes))
			{
				return ::vl::__vwsn::This(strings.Obj())->Yes();
			}
			else if ((__vwsn_switch_0 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectNo))
			{
				return ::vl::__vwsn::This(strings.Obj())->No();
			}
			else if ((__vwsn_switch_0 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectRetry))
			{
				return ::vl::__vwsn::This(strings.Obj())->Retry();
			}
			else if ((__vwsn_switch_0 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectAbort))
			{
				return ::vl::__vwsn::This(strings.Obj())->Abort();
			}
			else if ((__vwsn_switch_0 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectIgnore))
			{
				return ::vl::__vwsn::This(strings.Obj())->Ignore();
			}
			else if ((__vwsn_switch_0 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectTryAgain))
			{
				return ::vl::__vwsn::This(strings.Obj())->TryAgain();
			}
			else if ((__vwsn_switch_0 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectContinue))
			{
				return ::vl::__vwsn::This(strings.Obj())->Continue();
			}
			else
			{
				return ::vl::WString::Unmanaged(L"");
			}
		}
	}

	::vl::WString MessageBoxButtonTemplate::GetButtonAlt(::vl::presentation::INativeDialogService::MessageBoxButtonsOutput button)
	{
		{
			auto __vwsn_switch_1 = button;
			if ((__vwsn_switch_1 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectOK))
			{
				return ::vl::WString::Unmanaged(L"O");
			}
			else if ((__vwsn_switch_1 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectCancel))
			{
				return ::vl::WString::Unmanaged(L"C");
			}
			else if ((__vwsn_switch_1 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectYes))
			{
				return ::vl::WString::Unmanaged(L"Y");
			}
			else if ((__vwsn_switch_1 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectNo))
			{
				return ::vl::WString::Unmanaged(L"N");
			}
			else if ((__vwsn_switch_1 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectRetry))
			{
				return ::vl::WString::Unmanaged(L"R");
			}
			else if ((__vwsn_switch_1 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectAbort))
			{
				return ::vl::WString::Unmanaged(L"A");
			}
			else if ((__vwsn_switch_1 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectIgnore))
			{
				return ::vl::WString::Unmanaged(L"I");
			}
			else if ((__vwsn_switch_1 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectTryAgain))
			{
				return ::vl::WString::Unmanaged(L"T");
			}
			else if ((__vwsn_switch_1 == ::vl::presentation::INativeDialogService::MessageBoxButtonsOutput::SelectContinue))
			{
				return ::vl::WString::Unmanaged(L"K");
			}
			else
			{
				return ::vl::WString::Unmanaged(L"");
			}
		}
	}

	::vl::Ptr<::gaclib_controls::IDialogStringsStrings> MessageBoxButtonTemplate::GetStrings()
	{
		return this->__vwsn_prop_Strings;
	}
	void MessageBoxButtonTemplate::SetStrings(::vl::Ptr<::gaclib_controls::IDialogStringsStrings> __vwsn_value_)
	{
		if ((this->__vwsn_prop_Strings.Obj() != __vwsn_value_.Obj()))
		{
			(this->__vwsn_prop_Strings = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->StringsChanged)();
		}
	}

	::vl::Ptr<::vl::presentation::IMessageBoxDialogAction> MessageBoxButtonTemplate::GetAction()
	{
		return this->__vwsn_parameter_Action;
	}

	MessageBoxButtonTemplate::MessageBoxButtonTemplate(::vl::Ptr<::vl::presentation::IMessageBoxDialogAction> __vwsn_ctor_parameter_Action)
		: __vwsn_prop_ButtonControl(static_cast<::vl::presentation::controls::GuiButton*>(nullptr))
		, __vwsn_prop_Strings(::gaclib_controls::DialogStrings::Get(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US"))))
		, __vwsn_parameter_Action(::vl::Ptr<::vl::presentation::IMessageBoxDialogAction>())
	{
		(this->__vwsn_parameter_Action = __vwsn_ctor_parameter_Action);
		auto __vwsn_resource_ = ::vl::__vwsn::This(::vl::presentation::GetResourceManager())->GetResourceFromClassName(::vl::WString::Unmanaged(L"gaclib_controls::MessageBoxButtonTemplate"));
		auto __vwsn_resolver_ = ::vl::Ptr<::vl::presentation::GuiResourcePathResolver>(new ::vl::presentation::GuiResourcePathResolver(__vwsn_resource_, ::vl::__vwsn::This(__vwsn_resource_.Obj())->GetWorkingDirectory()));
		::vl::__vwsn::This(this)->SetResourceResolver(__vwsn_resolver_);
		::vl::__vwsn::This(this)->__vwsn_gaclib_controls_MessageBoxButtonTemplate_Initialize(this);
		this->__vwsn_instance_ctor_();
	}

	void MessageBoxButtonTemplate::__vwsn_instance_ctor_()
	{
		::vl::__vwsn::This(this->self)->SetButtonControl(::vl::__vwsn::This(this->self)->buttonControl);
	}

	MessageBoxButtonTemplate::~MessageBoxButtonTemplate()
	{
		this->FinalizeInstanceRecursively(static_cast<::vl::presentation::templates::GuiTemplate*>(this));
	}

/***********************************************************************
Class (::gaclib_controls::MessageBoxWindowConstructor)
***********************************************************************/

	void MessageBoxWindowConstructor::__vwsn_gaclib_controls_MessageBoxWindow_Initialize(::gaclib_controls::MessageBoxWindow* __vwsn_this_)
	{
		(this->self = __vwsn_this_);
		(this->ViewModel = ::vl::__vwsn::This(__vwsn_this_)->GetViewModel());
		{
			::vl::__vwsn::This(this->self)->SetIconVisible(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetSizeBox(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetMinimizedBox(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetMaximizedBox(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetShowInTaskBar(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetClientSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(240); __vwsn_temp__.y = static_cast<::vl::vint>(120); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_0 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetCellPadding(static_cast<::vl::vint>(10));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(10); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowsAndColumns(static_cast<::vl::vint>(3), static_cast<::vl::vint>(2));
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_1 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->__vwsn_precompile_2 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetRowsAndColumns(static_cast<::vl::vint>(3), static_cast<::vl::vint>(1));
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetRowOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_3 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->__vwsn_precompile_4 = ::vl::Ptr<::vl::presentation::elements::GuiSolidBackgroundElement>(::vl::reflection::description::Element_Constructor<::vl::presentation::elements::GuiSolidBackgroundElement>()));
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4.Obj())->SetColor(::vl::__vwsn::Parse<::vl::presentation::Color>(::vl::WString::Unmanaged(L"#FFFFFF")));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->SetOwnedElement(::vl::Ptr<::vl::presentation::elements::IGuiGraphicsElement>(this->__vwsn_precompile_4));
		}
		(this->__vwsn_precompile_5 = new ::vl::presentation::compositions::GuiBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(48); __vwsn_temp__.y = static_cast<::vl::vint>(48); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		(this->__vwsn_precompile_6 = ::vl::Ptr<::vl::presentation::elements::GuiImageFrameElement>(::vl::reflection::description::Element_Constructor<::vl::presentation::elements::GuiImageFrameElement>()));
		{
			::vl::__vwsn::This(this->__vwsn_precompile_6.Obj())->SetStretch(true);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetOwnedElement(::vl::Ptr<::vl::presentation::elements::IGuiGraphicsElement>(this->__vwsn_precompile_6));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_5));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_3));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_2));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_1));
		}
		(this->__vwsn_precompile_7 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->__vwsn_precompile_8 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_8)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_8)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_8)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_8)->SetRowsAndColumns(static_cast<::vl::vint>(3), static_cast<::vl::vint>(1));
			::vl::__vwsn::This(this->__vwsn_precompile_8)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_8)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_8)->SetRowOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_8)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_9 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_10 = new ::vl::presentation::controls::GuiLabel(::vl::presentation::theme::ThemeName::Label));
		}
		(this->__vwsn_precompile_11 = ::vl::__vwsn::This(this->__vwsn_precompile_10)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_11)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_10)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_8)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_9));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_8));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_7));
		}
		(this->__vwsn_precompile_12 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_12)->SetSite(static_cast<::vl::vint>(2), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(2));
		}
		(this->__vwsn_precompile_13 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_13)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_13)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_13)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_13)->SetRowsAndColumns(static_cast<::vl::vint>(1), static_cast<::vl::vint>(3));
			::vl::__vwsn::This(this->__vwsn_precompile_13)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_13)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_13)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_13)->SetColumnOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_14 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->buttonStack = new ::vl::presentation::compositions::GuiRepeatStackComposition());
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"buttonStack"), ::vl::__vwsn::Box(this->buttonStack));
		{
			::vl::__vwsn::This(this->buttonStack)->SetItemTemplate(vl::Func(::vl_workflow_global::__vwsnf90_GuiFakeDialogServiceUI_gaclib_controls_MessageBoxWindowConstructor___vwsn_gaclib_controls_MessageBoxWindow_Initialize_(this)));
		}
		{
			::vl::__vwsn::This(this->buttonStack)->SetPadding(static_cast<::vl::vint>(5));
		}
		{
			::vl::__vwsn::This(this->buttonStack)->SetDirection(::vl::presentation::compositions::GuiStackComposition::Direction::Horizontal);
		}
		{
			::vl::__vwsn::This(this->buttonStack)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->buttonStack)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->buttonStack));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_13)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_14));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_12)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_13));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_12));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_0));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_6.Obj())->SetImage(::vl::__vwsn::This(this->self)->GetIcon(::vl::__vwsn::This(this->ViewModel.Obj())->GetIcon()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_10)->SetText(::vl::__vwsn::This(this->ViewModel.Obj())->GetText());
		}
		{
			::vl::__vwsn::This(this->buttonStack)->SetItemSource(::vl::Ptr<::vl::reflection::description::IValueEnumerable>(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueReadonlyList>(::vl::__vwsn::This(this->ViewModel.Obj())->GetButtons())));
		}
		{
			::vl::__vwsn::This(this->self)->SetText(::vl::__vwsn::This(this->ViewModel.Obj())->GetTitle());
		}
	}

	MessageBoxWindowConstructor::MessageBoxWindowConstructor()
		: self(static_cast<::gaclib_controls::MessageBoxWindow*>(nullptr))
		, ViewModel(::vl::Ptr<::vl::presentation::IMessageBoxDialogViewModel>())
		, buttonStack(static_cast<::vl::presentation::compositions::GuiRepeatStackComposition*>(nullptr))
		, __vwsn_precompile_0(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_1(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_2(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_3(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_4(::vl::Ptr<::vl::presentation::elements::GuiSolidBackgroundElement>())
		, __vwsn_precompile_5(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_6(::vl::Ptr<::vl::presentation::elements::GuiImageFrameElement>())
		, __vwsn_precompile_7(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_8(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_9(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_10(static_cast<::vl::presentation::controls::GuiLabel*>(nullptr))
		, __vwsn_precompile_11(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_12(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_13(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_14(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
	{
	}

/***********************************************************************
Class (::gaclib_controls::MessageBoxWindow)
***********************************************************************/

	::vl::Ptr<::vl::presentation::INativeImage> MessageBoxWindow::GetIcon(::vl::presentation::INativeDialogService::MessageBoxIcons icon)
	{
		auto iconUri = ::vl::WString::Unmanaged(L"Images/None");
		{
			auto __vwsn_switch_2 = ::vl::__vwsn::This(this->GetViewModel().Obj())->GetIcon();
			if ((__vwsn_switch_2 == ::vl::presentation::INativeDialogService::MessageBoxIcons::IconError))
			{
				(iconUri = ::vl::WString::Unmanaged(L"Images/Error"));
			}
			else if ((__vwsn_switch_2 == ::vl::presentation::INativeDialogService::MessageBoxIcons::IconQuestion))
			{
				(iconUri = ::vl::WString::Unmanaged(L"Images/Question"));
			}
			else if ((__vwsn_switch_2 == ::vl::presentation::INativeDialogService::MessageBoxIcons::IconWarning))
			{
				(iconUri = ::vl::WString::Unmanaged(L"Images/Warning"));
			}
			else if ((__vwsn_switch_2 == ::vl::presentation::INativeDialogService::MessageBoxIcons::IconInformation))
			{
				(iconUri = ::vl::WString::Unmanaged(L"Images/Information"));
			}
		}
		return ::vl::__vwsn::This(::vl::__vwsn::Ensure(::vl::__vwsn::SharedPtrCast<::vl::presentation::GuiImageData>(::vl::__vwsn::This(this->self)->ResolveResource(::vl::WString::Unmanaged(L"res"), iconUri, true).Obj())).Obj())->GetImage();
	}

	::vl::Ptr<::vl::presentation::IMessageBoxDialogViewModel> MessageBoxWindow::GetViewModel()
	{
		return this->__vwsn_parameter_ViewModel;
	}

	MessageBoxWindow::MessageBoxWindow(::vl::Ptr<::vl::presentation::IMessageBoxDialogViewModel> __vwsn_ctor_parameter_ViewModel)
		: ::vl::presentation::controls::GuiWindow(::vl::presentation::theme::ThemeName::Window)
		, __vwsn_parameter_ViewModel(::vl::Ptr<::vl::presentation::IMessageBoxDialogViewModel>())
	{
		(this->__vwsn_parameter_ViewModel = __vwsn_ctor_parameter_ViewModel);
		auto __vwsn_resource_ = ::vl::__vwsn::This(::vl::presentation::GetResourceManager())->GetResourceFromClassName(::vl::WString::Unmanaged(L"gaclib_controls::MessageBoxWindow"));
		auto __vwsn_resolver_ = ::vl::Ptr<::vl::presentation::GuiResourcePathResolver>(new ::vl::presentation::GuiResourcePathResolver(__vwsn_resource_, ::vl::__vwsn::This(__vwsn_resource_.Obj())->GetWorkingDirectory()));
		::vl::__vwsn::This(this)->SetResourceResolver(__vwsn_resolver_);
		::vl::__vwsn::This(this)->__vwsn_gaclib_controls_MessageBoxWindow_Initialize(this);
		this->__vwsn_instance_ctor_();
	}

	void MessageBoxWindow::__vwsn_instance_ctor_()
	{
		auto defaultButton = ::vl::__vwsn::This(::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueReadonlyList>(::vl::__vwsn::This(this->GetViewModel().Obj())->GetButtons()).Obj())->IndexOf(::vl::__vwsn::Box(::vl::__vwsn::This(this->GetViewModel().Obj())->GetDefaultButton()));
		auto buttonControl = ::vl::__vwsn::This(::vl::__vwsn::Ensure(::vl::__vwsn::RawPtrCast<::gaclib_controls::MessageBoxButtonTemplate>(::vl::__vwsn::This(::vl::__vwsn::This(this->buttonStack)->GetStackItems()[defaultButton])->Children()[static_cast<::vl::vint>(0)])))->GetButtonControl();
		::vl::__vwsn::This(buttonControl)->SetFocused();
	}

	MessageBoxWindow::~MessageBoxWindow()
	{
		this->FinalizeInstanceRecursively(static_cast<::vl::presentation::controls::GuiControlHost*>(this));
	}

/***********************************************************************
Class (::gaclib_controls::SimpleFontDialogWindowConstructor)
***********************************************************************/

	void SimpleFontDialogWindowConstructor::__vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize(::gaclib_controls::SimpleFontDialogWindow* __vwsn_this_)
	{
		(this->self = __vwsn_this_);
		(this->ViewModel = ::vl::__vwsn::This(__vwsn_this_)->GetViewModel());
		{
			::vl::__vwsn::This(this->self)->SetIconVisible(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetMinimizedBox(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetMaximizedBox(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetShowInTaskBar(false);
		}
		{
			::vl::__vwsn::This(this->self)->SetClientSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(360); __vwsn_temp__.y = static_cast<::vl::vint>(360); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_0 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetCellPadding(static_cast<::vl::vint>(10));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowsAndColumns(static_cast<::vl::vint>(3), static_cast<::vl::vint>(3));
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_0)->SetColumnOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_1 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(3));
		}
		(this->__vwsn_precompile_2 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetCellPadding(static_cast<::vl::vint>(10));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(10); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetRowsAndColumns(static_cast<::vl::vint>(1), static_cast<::vl::vint>(2));
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(0.5); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_2)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(0.5); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_3 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->nameControl = new ::gaclib_controls::FontNameControl(::vl::Ptr<::vl::presentation::ICommonFontDialogViewModel>(this->ViewModel)));
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"nameControl"), ::vl::__vwsn::Box(this->nameControl));
		(this->__vwsn_precompile_4 = ::vl::__vwsn::This(this->nameControl)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_4)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_3)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->nameControl)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_3));
		}
		(this->__vwsn_precompile_5 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->SetSite(static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		(this->sizeControl = new ::gaclib_controls::FontSizeControl());
		::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"sizeControl"), ::vl::__vwsn::Box(this->sizeControl));
		(this->__vwsn_precompile_6 = ::vl::__vwsn::This(this->sizeControl)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_6)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_5)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->sizeControl)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_2)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_5));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_1)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_2));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_1));
		}
		(this->__vwsn_precompile_7 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.y = static_cast<::vl::vint>(48); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(0), static_cast<::vl::vint>(1), static_cast<::vl::vint>(3));
		}
		{
			(this->__vwsn_precompile_8 = new ::vl::presentation::controls::GuiControl(::vl::presentation::theme::ThemeName::GroupBox));
		}
		(this->__vwsn_precompile_13 = ::vl::__vwsn::This(this->__vwsn_precompile_8)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_13)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_9 = new ::vl::presentation::compositions::GuiTableComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetBorderVisible(false);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren);
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetRowsAndColumns(static_cast<::vl::vint>(3), static_cast<::vl::vint>(3));
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetRowOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetRowOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetColumnOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetColumnOption(static_cast<::vl::vint>(1), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::MinSize; return __vwsn_temp__; }());
			::vl::__vwsn::This(this->__vwsn_precompile_9)->SetColumnOption(static_cast<::vl::vint>(2), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast<double>(1.0); return __vwsn_temp__; }());
		}
		(this->__vwsn_precompile_10 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_10)->SetSite(static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_11 = new ::vl::presentation::controls::GuiLabel(::vl::presentation::theme::ThemeName::Label));
		}
		(this->__vwsn_precompile_12 = ::vl::__vwsn::This(this->__vwsn_precompile_11)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_12)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_11)->SetText(::vl::WString::Unmanaged(L"ABCxyz"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_10)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_11)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_9)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_10));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->__vwsn_precompile_8)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_9));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_7)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_8)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_7));
		}
		(this->__vwsn_precompile_14 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->SetSite(static_cast<::vl::vint>(2), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_15 = new ::vl::presentation::controls::GuiButton(::vl::presentation::theme::ThemeName::Button));
		}
		(this->__vwsn_precompile_16 = ::vl::__vwsn::This(this->__vwsn_precompile_15)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_16)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(80); __vwsn_temp__.y = static_cast<::vl::vint>(24); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_16)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_15)->SetAlt(::vl::WString::Unmanaged(L"O"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_14)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_15)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_14));
		}
		(this->__vwsn_precompile_17 = new ::vl::presentation::compositions::GuiCellComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_17)->SetSite(static_cast<::vl::vint>(2), static_cast<::vl::vint>(2), static_cast<::vl::vint>(1), static_cast<::vl::vint>(1));
		}
		{
			(this->__vwsn_precompile_18 = new ::vl::presentation::controls::GuiButton(::vl::presentation::theme::ThemeName::Button));
		}
		(this->__vwsn_precompile_19 = ::vl::__vwsn::This(this->__vwsn_precompile_18)->GetBoundsComposition());
		{
			::vl::__vwsn::This(this->__vwsn_precompile_19)->SetPreferredMinSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(80); __vwsn_temp__.y = static_cast<::vl::vint>(24); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_19)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }());
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_18)->SetAlt(::vl::WString::Unmanaged(L"C"));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_17)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->__vwsn_precompile_18)->GetBoundsComposition()));
		}
		{
			::vl::__vwsn::This(this->__vwsn_precompile_0)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_17));
		}
		{
			::vl::__vwsn::This(::vl::__vwsn::This(this->self)->GetContainerComposition())->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(this->__vwsn_precompile_0));
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc49_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf78_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc50_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf79_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc51_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf80_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc52_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf81_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf82_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->__vwsn_precompile_15)->Clicked, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc53_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf83_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_event_handler_ = vl::Func(::vl_workflow_global::__vwsnf84_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(this->__vwsn_precompile_18)->Clicked, __vwsn_event_handler_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc54_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf85_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
		{
			auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc55_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize__vl_reflection_description_IValueSubscription(this));
			::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf86_GuiFakeDialogServiceUI_gaclib_controls_SimpleFontDialogWindowConstructor___vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize_(this)));
			::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_);
		}
	}

	SimpleFontDialogWindowConstructor::SimpleFontDialogWindowConstructor()
		: self(static_cast<::gaclib_controls::SimpleFontDialogWindow*>(nullptr))
		, ViewModel(::vl::Ptr<::vl::presentation::ISimpleFontDialogViewModel>())
		, nameControl(static_cast<::gaclib_controls::FontNameControl*>(nullptr))
		, sizeControl(static_cast<::gaclib_controls::FontSizeControl*>(nullptr))
		, __vwsn_precompile_0(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_1(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_2(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_3(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_4(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_5(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_6(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_7(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_8(static_cast<::vl::presentation::controls::GuiControl*>(nullptr))
		, __vwsn_precompile_9(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr))
		, __vwsn_precompile_10(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_11(static_cast<::vl::presentation::controls::GuiLabel*>(nullptr))
		, __vwsn_precompile_12(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_13(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_14(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_15(static_cast<::vl::presentation::controls::GuiButton*>(nullptr))
		, __vwsn_precompile_16(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
		, __vwsn_precompile_17(static_cast<::vl::presentation::compositions::GuiCellComposition*>(nullptr))
		, __vwsn_precompile_18(static_cast<::vl::presentation::controls::GuiButton*>(nullptr))
		, __vwsn_precompile_19(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr))
	{
	}

/***********************************************************************
Class (::gaclib_controls::SimpleFontDialogWindow)
***********************************************************************/

	::vl::Ptr<::gaclib_controls::IDialogStringsStrings> SimpleFontDialogWindow::GetStrings()
	{
		return this->__vwsn_prop_Strings;
	}
	void SimpleFontDialogWindow::SetStrings(::vl::Ptr<::gaclib_controls::IDialogStringsStrings> __vwsn_value_)
	{
		if ((this->__vwsn_prop_Strings.Obj() != __vwsn_value_.Obj()))
		{
			(this->__vwsn_prop_Strings = __vwsn_value_);
			::vl::__vwsn::EventInvoke(this->StringsChanged)();
		}
	}

	::vl::Ptr<::vl::presentation::ISimpleFontDialogViewModel> SimpleFontDialogWindow::GetViewModel()
	{
		return this->__vwsn_parameter_ViewModel;
	}

	SimpleFontDialogWindow::SimpleFontDialogWindow(::vl::Ptr<::vl::presentation::ISimpleFontDialogViewModel> __vwsn_ctor_parameter_ViewModel)
		: ::vl::presentation::controls::GuiWindow(::vl::presentation::theme::ThemeName::Window)
		, __vwsn_prop_Strings(::gaclib_controls::DialogStrings::Get(::vl::__vwsn::Parse<::vl::Locale>(::vl::WString::Unmanaged(L"en-US"))))
		, __vwsn_parameter_ViewModel(::vl::Ptr<::vl::presentation::ISimpleFontDialogViewModel>())
	{
		(this->__vwsn_parameter_ViewModel = __vwsn_ctor_parameter_ViewModel);
		auto __vwsn_resource_ = ::vl::__vwsn::This(::vl::presentation::GetResourceManager())->GetResourceFromClassName(::vl::WString::Unmanaged(L"gaclib_controls::SimpleFontDialogWindow"));
		auto __vwsn_resolver_ = ::vl::Ptr<::vl::presentation::GuiResourcePathResolver>(new ::vl::presentation::GuiResourcePathResolver(__vwsn_resource_, ::vl::__vwsn::This(__vwsn_resource_.Obj())->GetWorkingDirectory()));
		::vl::__vwsn::This(this)->SetResourceResolver(__vwsn_resolver_);
		::vl::__vwsn::This(this)->__vwsn_gaclib_controls_SimpleFontDialogWindow_Initialize(this);
		this->__vwsn_instance_ctor_();
	}

	void SimpleFontDialogWindow::__vwsn_instance_ctor_()
	{
		::vl::__vwsn::This(this->nameControl)->InitValue(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFontFamily());
		::vl::__vwsn::This(this->sizeControl)->InitValue(::vl::__vwsn::This(this->GetViewModel().Obj())->GetFontSize());
	}

	SimpleFontDialogWindow::~SimpleFontDialogWindow()
	{
		this->FinalizeInstanceRecursively(static_cast<::vl::presentation::controls::GuiControlHost*>(this));
	}

}
#undef GLOBAL_SYMBOL
#undef GLOBAL_NAME
#undef GLOBAL_OBJ

#if defined( _MSC_VER)
#pragma warning(pop)
#elif defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#endif


/***********************************************************************
.\UTILITIES\FAKESERVICES\DIALOGS\SOURCE\GUIFAKEDIALOGSERVICEUIRESOURCE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		namespace user_resource
		{
			using namespace collections;
			using namespace stream;
			using namespace controls;

			class GuiFakeDialogServiceUIResourceReader
			{
			public:
				static const vint parserBufferLength = 32417; // 32417 bytes before compressing
				static const vint parserBufferBlock = 1024;
				static const vint parserBufferRemain = 673;
				static const vint parserBufferRows = 32;
				static const char* parserBuffer[32];

				static void ReadToStream(vl::stream::MemoryStream& stream)
				{
					DecompressStream(parserBuffer, false, parserBufferRows, parserBufferBlock, parserBufferRemain, stream);
				}
			};

			const char* GuiFakeDialogServiceUIResourceReader::parserBuffer[] = {
				"\x60\x00\x00\x00\x00\x00\x00\x00\x60\x00\x00\x00\x3C\x52\x65\x73\x6F\x75\x72\x63\x65\x4D\x65\x74\x61\x64\x61\x74\x61\x20\x4E\x61\x6D\x65\x3D\x22\x47\x75\x69\x46\x61\x6B\x65\x44\x69\x61\x6C\x6F\x67\x53\x65\x72\x76\x69\x63\x65\x55\x49\x22\x20\x56\x65\x72\x73\x69\x6F\x6E\x3D\x22\x31\x2E\x30\x22\x3E\x3C\x44\x65\x70\x65\x6E\x64\x65\x6E\x63\x69\x65\x73\x2F\x3E\x3C\x2F\x52\x65\x73\x6F\x75\x72\x63\x65\x4D\x65\x74\x61\x64\x61\x74\x61\x3E\x06\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x4C\x6F\x63\x61\x6C\x69\x7A\x65\x64\x53\x74\x72\x69\x6E\x67\x73\x08\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x49\x6E\x73\x74\x61\x6E\x63\x65\x04\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x54\x65\x78\x74\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x49\x6D\x61\x67\x65\x0F\x00\x00\x00\x00\x00\x00\x00\x0F\x00\x00\x00\x43\x6C\x61\x73\x73\x4E\x61\x6D\x65\x52\x65\x63\x6F\x72\x64\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x58\x6D\x6C\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x43\x6F\x6C\x6F\x72\x44\x69\x61\x6C\x6F\x67\x43\x6F\x6D\x70\x6F\x6E\x65\x6E\x74\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x46\x69\x6C\x65\x44\x69\x61\x6C\x6F\x67\x43\x6F\x6D\x70\x6F\x6E\x65\x6E\x74\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x46\x6F\x6E\x74\x44\x69\x61\x6C\x6F\x67\x43\x6F\x6D\x70\x6F\x6E\x65\x6E\x74\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x00\x00\x47\x61\x63\x47\x65\x6E\x43\x6F\x6E\x66\x69\x67\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x43\x70\x70\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x0D\x00\x00\x00\x00\x00\x00\x00\x0D\x00\x00\x00\x43\x70\x70\x43\x6F\x6D\x70\x72\x65\x73\x73\x65\x64\x1A\x00\x00\x00\x00\x00\x00\x00\x1A\x00\x00\x00\x47\x75\x69\x46\x61\x6B\x65\x44\x69\x61\x6C\x6F\x67\x53\x65\x72\x76\x69\x63\x65\x55\x49\x2E\x63\x70\x70\x02\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x4E\x61\x6D\x65\x16\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00\x00\x47\x75\x69\x46\x61\x6B\x65\x44\x69\x61\x6C\x6F\x67\x53\x65\x72\x76\x69\x63\x65\x55\x49\x02\x00\x00\x00\x00\x00\x00\x00\x0D\x00\x00\x00\x00\x00\x00\x00\x0D\x00\x00\x00\x4E\x6F\x72\x6D\x61\x6C\x49\x6E\x63\x6C\x75\x64\x65\x13\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x2E\x2E\x2F\x2E\x2E\x2F\x2E\x2E\x2F\x2E\x2E\x2F\x47\x61\x63\x55\x49\x2E\x68\x02\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x52\x65\x66\x6C\x65\x63\x74\x69\x6F\x6E\x49\x6E\x63\x6C\x75\x64\x65\x3C\x00\x00\x00\x00\x00\x00\x00\x3C\x00\x00\x00\x2E\x2E\x2F\x2E\x2E\x2F\x2E\x2E\x2F\x2E\x2E\x2F\x52\x65\x66\x6C\x65\x63\x74\x69\x6F\x6E\x2F\x54\x79\x70\x65\x44\x65\x73\x63\x72\x69\x70\x74\x6F\x72\x73\x2F\x47\x75\x69\x52\x65\x66\x6C\x65\x63\x74\x69\x6F\x6E\x50\x6C\x75\x67\x69\x6E\x2E\x68\x02\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x00\x00\x53\x6F\x75\x72\x63\x65\x46\x6F\x6C\x64\x65\x72\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x53\x6F\x75\x72\x63\x65\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x49\x6D\x61\x67\x65\x73\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x45\x72\x72\x6F\x72\xDA\x14\x00\x00\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\xF0\x00\x00\x00\xF0\x08\x06\x00\x00\x00\x3E\x55\xE9\x92\x00\x00\x00\x06\x62\x4B\x47\x44\x00\xFF\x00\xFF\x00\xFF\xA0\xBD\xA7\x93\x00\x00\x14\x8F\x49\x44\x41\x54\x78\x9C\xED\x9D\x79\xB0\x9F\x55\x79\xC7\x3F\xF7\xE6\x26\x21\x85\x34\x81\x84\x80\x20\x92\xB0\x59\x51\xF6\xAD\x42\x14\xA4\x99\x5A\xA6\x82\x6C\x42\x6A\x2D\xAB",
				"\x20\x8B\x0B\xE0\x42\xC7\x5A\x44\x16\xC5\xA5\x15\x6C\x1D\xA1\xAD\x54\x10\x24\x41\xDB\x8E\x55\x2C\x65\x06\x87\x2A\xA0\x6C\xB2\x86\x2D\x21\x09\x81\x11\x59\xB2\x10\x48\x02\xDC\x24\xB7\x7F\x9C\xDF\x6F\x72\x8D\x97\xBB\xFD\x9E\xE7\x39\xEF\x79\xDF\xEF\x67\xE6\x99\x7B\xE7\xE6\xE6\xDC\xF3\x3C\xE7\x79\xDE\xDF\x79\xCF\x79\xCE\x73\x40\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x88\xBC\x74\xE5\xEE\x80\x18\x36\x53\x80\xE9\x2D\xD9\x1E\x78\x4B\xEB\x67\x53\x80\xA9\xAD\xAF\xE3\x81\x49\xAD\xDF\x1F\x07\x6C\xDA\xFA\x7E\x15\xF0\x46\xEB\xFB\x15\xC0\xEB\xC0\xD2\x8D\xE4\x39\x60\x71\x3F\x59\xE6\xA5\x88\xB0\x43\x01\x5C\x3D\xA6\x01\xBB\xB7\x64\xB7\xD6\xD7\x9D\x81\x89\xC1\xFD\x58\x09\xCC\x07\x1E\x6E\xC9\x43\x2D\x79\x21\xB8\x1F\x62\x10\x14\xC0\x79\x19\x03\xFC\x09\x70\x10\x30\xB3\x25\x33\xB2\xF6\x68\x68\x9E\x03\xEE\x03\x6E\x07\xEE\x00\xEE\x66\xC3\xA7\xBB\x08\x46\x01\x1C\xCF\x2E\xC0\x61\xC0\x5F\x00\xEF\x61\xC3\x34\xB7\x54\x5E\x05\x7E\x01\xFC\x0F\x70\x33\xB0\x20\x6F\x77\x84\xB0\x65\x0C\xF0\x3E\xE0\x9F\x49\xCE\xDD\x57\x73\x99\x0F\x7C\x0B\x38\x18\xE8\x36\xB0\x9F\x10\xE1\x74\x93\xA6\xC3\x57\x00\xBF\x25\x7F\x50\xE5\x92\x17\x81\x6B\x81\x59\x28\x98\x45\x01\xBC\x0D\xB8\x10\x58\x42\xFE\xE0\xA9\x9A\x3C\x0D\x7C\x11\x78\xEB\x68\x8D\x2B\x84\x07\x3D\xC0\x51\xC0\x4D\xC0\x3A\xF2\x07\x4A\xD5\x65\x2D\xF0\x53\xE0\x48\xD2\xEB\x85\x10\x59\xD8\x0C\x38\x1D\x78\x82\xFC\x41\x51\xAA\x2C\x02\xCE\x07\x26\x8F\xD0\xF6\x42\x8C\x9A\x6D\x81\xAF\x02\xCB\xC9\x1F\x00\x75\x91\xE5\xC0\x65\xA4\xE4\x14\x21\x5C\xD8\x92\xE4\x64\xAB\xC9\xEF\xF0\x75\x95\xD7\x81\xAB\x50\x20\x0B\x43\xA6\x90\x16\xA6\x56\x92\xDF\xC1\x9B\x22\xAB\x48\x2B\xF8\x5B\x0D\x3D\x3C\x42\x0C\xCC\x78\xE0\x73\xC0\xCB\xE4\x77\xE8\xA6\xCA\x0A\xE0\x33\xA4\xBC\x6E\x21\x86\xCD\xE1\x34\x23\xE9\xA2\x14\x99\x0F\x7C\x68\xD0\x11\x13\x02\x78\x3B\x70\x2B\xF9\x1D\x56\x32\xB0\xFC\x2F\xE9\x60\x87\x10\xBF\x47\x0F\x69\x3B\x63\x0D\xF9\x9D\x54\x32\xB8\xAC\x21\xAD\x49\x68\x5A\x2D\x00\xD8\x13\xB8\x97\xFC\x8E\x29\x19\x99\x3C\x08\xEC\x3F\xC0\x78\x8A\x86\x30\x16\xB8\x84\x94\x19\x94\xDB\x19\x25\xA3\x93\x5E\xE0\x4B\xA4\x19\x94\x68\x10\x33\x48\xE7\x59\x73\x3B\xA0\xC4\x46\xEE\x42\xEF\xC6\x8D\xE1\x54\xE0\x15\xF2\x3B\x9D\xC4\x56\x56\x02\x27\xD1\x30\x9A\x74\xA0\x7F\x02\xF0\x1D\xE0\xC4\xDC\x1D\xE9\x80\x35\xC0\x53\xA4\x9A\x55\x8B\x5A\x5F\x9F\x67\x43\x5D\xAB\x97\x48\x7B\xA7\x90\xAA\x64\xAC\x6A\x7D\xBF\x29\x1B\x16\x7D\x26\xB3\xA1\x86\xD6\x14\x52\xB2\xC4\x0C\x52\xAD\xAD\x19\xC0\x0E\x24\x5B\x95\xCA\xD5\xC0\xD9\xC0\x6B\xB9\x3B\x12\x41\x53\x02\x78\x06\xF0\x1F\xC0\x5E\xB9\x3B\x32\x02\x96\x01\x77\x02\xBF\x21\xD5\xA4\x7A\x90\x14\xBC\xEB\x9D\xFF\xEE\x18\x60\x47\x60\x0F\x52\x4D\xAE\xBD\x81\x03\x81\xCD\x9D\xFF\xAE\x25\xF7\x01\xC7\x90\x8E\x30\x8A\xC2\x79\x3F\xE9\x93\x29\xF7\x14\x6F\x28\x79\x11\xF8\x01\xF0\x51\x60\x57\xAA\xF5\x70\xED\x22\xF5\xE9\x34\xE0\x06\xCA\xB1\xE7\x2C\x0F\x63\x88\x38\xCE\xA4\xDA\xAB\xCC\x0F\x91\x56\x51\x0F\xA0\xAC\xB3\xB1\x63\x80\x3F\x05\x2E\x22\xCD\x0E\x72\xDB\xF1\xCD\xA4\x97\x74\xE4\x53\x14\x46\x37\xF0\x75\xF2\x3B\xD0\x40\xF2\x28\x70\x01\xA9\x1A\x65\x5D\xD8\x95\x94\x5C\xF1\x18\xF9\xED\x3B\x90\x5C\x46\xB5\x66\x34\x62\x10\x26\x00\x3F\x22\xBF\xD3\xF4\x97\x55\xC0\xF7\x48\xEF\x92\x75\x67\x26\x70\x0D\xD5\x3B\x76\x39\x17\xD8\xC4\x51\x6F\x61\xC0\x44\xE0\xFF\xC8\xEF\x2C\x6D\x59\x04\x9C\xC3\x86\xDB\x12\x9A\xC4\x64\xE0\x3C\xD2\x4A\x79\xEE\x71\x68\xCB\xCF\x49\x95\x54\x44\x05\xD9\x1C\xF8\x35\xF9\x9D\xA4\x8F\x54\xEC\xFC\x38\xCA\x7A\xAF\xF5\xA2\x07\x98\x4D\x75\xD2\x55\xEF\x44\x25\x7C\x2A\xC7\x34\xE0\x7E\xF2\x3B\xC7\x43\xA4\x63\x6F\x7A\xDF\x1A\x98\x59\xC0\x3D\xE4\x1F\xA7\xDF\x90\x2A\xAC\x88\x0A\xB0\x25\x30\x8F\xBC\x0E\x31\x8F\x54\x65\x51\x81\x3B\x34\x5D\xC0\xD1\xE4\x5F\xF0\x7A\x98\x94\xD0\x22\x32\x32\x89\xBC\x53\xB3\x65\xA4\x63\x88\x3A\xDA\x36\x72\x7A\x48\x5B\x3C\x2F\x92\x6F\xFC\x1E\x00\xB6\xF0\x56\x54\x0C\xCC\x44\xF2\xBD\xF3\xAE\x23\x5D\x95\xA2\xC1\xEF\x9C\xA9\xC0\x95\xA4\x0C\xB3\x1C\x63\x79\x27\x5A\xD8\x0A\x67\x02\x70\x1B\x79\x06\x7C\x1E\xCD\xD8\x0E\x8A\x66\x26\xF9\xA6\xD5\xB7\xA2\x2D\xA6\x30\xBA\xC9\xB3\xCF\xDB\x3E\x7B\x3A\xDE\x5F",
				"\xC5\xC6\x32\x9E\x74\x46\xBB\x97\xF8\xF1\x9D\x83\xD6\x30\x42\xF8\x06\xF1\x83\xBB\x88\x74\x87\xAF\x88\x61\x7F\x52\x21\xBB\xE8\x71\xFE\x72\x84\x72\x4D\xE6\x4C\xE2\x07\xF5\xDF\xD0\x3B\x52\x0E\x26\x92\xB2\xD7\xA2\xC7\xFB\xB4\x00\xDD\x1A\xC9\xFB\x89\x3D\x98\xB0\x1A\x38\x21\x44\x33\x31\x18\xA7\x10\x5B\x6C\xB0\x17\xF8\xB3\x10\xCD\x1A\xC4\xF6\xC4\x6E\x37\x2C\x01\xF6\x0B\xD1\x4C\x0C\x87\xBD\x80\x85\xC4\x8D\xFF\x52\xD2\x19\x72\x61\xC0\x04\x52\xE6\x4C\xD4\xE0\xDD\x86\xB6\x87\xAA\xC8\x54\xE0\x97\xC4\xF9\xC1\xDD\x68\x65\xDA\x84\xAB\x89\x1B\x34\x9D\x58\xA9\x36\xE3\x81\xEB\x88\xF3\x87\x6B\x63\xD4\xAA\x2F\xA7\x12\x37\x58\x17\xA1\x6D\x84\x12\xE8\x22\xAD\x16\x47\xF9\x85\xD6\x41\x46\xC9\x8E\xC4\xDC\x08\xB8\x9E\x74\xEC\x4D\x94\xC5\xD9\xC4\x64\x6F\xBD\x82\x4A\xD6\x8E\x98\x1E\xE0\x57\xC4\x04\xEF\x27\x82\x74\x12\xF6\x9C\x4E\x4A\x6B\xF5\xF6\x93\xBB\x49\x17\x01\x88\x61\x72\x31\xFE\x83\xB2\x8E\xB2\x4B\xCC\x8A\xC4\x49\xC4\x04\xF1\x85\x31\xEA\x94\xCF\x7E\xF8\xEF\xF7\xAE\x07\x3E\x16\xA5\x90\x70\xE7\x4C\xFC\xA7\xD3\xBD\xC0\x3E\x51\x0A\x95\x4A\x0F\x31\x5B\x46\x9F\x8D\x52\x48\x84\x71\x0E\xFE\x7E\xF3\x20\x9A\x4A\x0F\xCA\xDF\xE1\x3F\x08\x17\x85\x69\x23\xA2\xB9\x0C\x7F\xFF\x39\x3F\x4C\x9B\xC2\xD8\x05\xFF\x94\xB9\x1B\xD0\x56\x51\x9D\xE9\x02\xBE\x8F\xAF\x0F\xAD\x06\x76\x8A\x52\xA8\x24\x6E\xC5\xD7\xF0\xB7\xA1\xCA\x19\x4D\x60\x13\xFC\x33\xB6\x6E\x0E\xD3\xA6\x10\x8E\xC2\xD7\xE0\x0B\x51\x7A\x64\x93\x98\x4A\xBA\x17\xC9\xD3\xA7\x3E\x10\xA6\x4D\xC5\x19\x07\x3C\x89\x9F\xA1\xD7\xA0\xD5\xC3\x26\xB2\x27\xBE\xC5\xE5\x17\xA0\xE2\x0E\x00\xFC\x2D\xBE\x4F\xCA\x93\xE3\x54\x11\x15\xE3\x6F\xF0\xF5\xAD\xC6\x67\xF0\x4D\x05\x5E\xC6\xCF\xC0\xDF\x8D\x53\x45\x54\x94\x6B\xF0\xF3\xAF\xE5\x34\xFC\xD5\xCC\xF3\x02\xB2\x05\xA4\xAA\x0E\xA2\xD9\x6C\x86\xEF\x2B\xDA\xA5\x71\xAA\x54\x8B\xAD\x49\x97\x7E\x79\x18\xB5\x97\x74\xFD\xA5\x10\x90\xB2\xFB\xDE\xC0\xC7\xD7\x5E\x25\xDD\x0C\xD2\x38\x2E\xC7\xEF\xA9\x78\x61\x9C\x1A\xA2\x10\x2E\xC1\xCF\xDF\xBE\x11\xA8\x47\x25\xD8\x16\xBF\xA4\x8D\x79\x68\xBF\x57\xFC\x21\x9B\xE0\x57\x77\x7A\x35\x69\x46\xD9\x18\xBE\x86\x8F\x21\xD7\xA1\xF2\xAF\xE2\xCD\x79\x37\x7E\x27\x97\x1A\xF3\x2E\x3C\x91\xB4\x7A\xE7\x61\xC4\x6F\x07\xEA\x21\xCA\xE4\x2A\x7C\x7C\x6F\x29\x0D\x29\x3F\x7C\x2E\x3E\x06\x5C\x06\x4C\x09\xD4\x43\x94\xC9\x16\xA4\x60\xF3\xF0\xC1\x4F\x06\xEA\x91\x85\x31\xC0\x53\xF8\x18\xEF\xEC\x40\x3D\x44\xD9\x78\x7D\x88\x2C\x22\x1D\x89\xAD\x2D\x5E\x39\xCF\xF3\xA8\xB9\xE1\x84\x29\x63\xF1\x5B\xD0\xFA\x60\xA0\x1E\xE1\xFC\x0C\x1F\xA3\x1D\x19\xA9\x84\xA8\x05\xC7\xE2\xE3\x8B\x3F\x89\x54\x22\x92\xED\xF0\x29\x95\x73\x2F\x3A\xE3\x2B\x46\x4E\x17\x70\x3F\xF6\xFE\xB8\x96\xE4\xEB\xB5\xE3\x4B\xF8\x3C\xF1\x0E\x8B\x54\x42\xD4\x8A\x23\xF0\xF1\xC9\x2F\x44\x2A\x11\x41\x37\xE9\xBE\x21\x6B\x43\xDD\x1D\xA9\x84\xA8\x1D\x5D\xC0\x7D\xD8\xFB\xE5\x22\x6A\x36\x2B\x3C\x18\x9F\x27\xDD\x71\x91\x4A\x88\x5A\xF2\x61\x7C\x7C\xF3\xC0\x48\x25\xBC\xF9\x36\x3E\x4F\x39\xAD\x3C\x8B\x4E\xE9\x01\x16\x63\xEF\x9F\x97\x07\xEA\xE0\xCA\x18\xE0\x39\xEC\x0D\x74\x4E\xA4\x12\xA2\xD6\x9C\x87\xBD\x7F\x3E\x4B\x7A\x75\x2C\x9E\x43\xB1\x37\xCE\x6A\x60\xF3\x48\x25\x44\xAD\x99\x8C\xCF\xD1\xD6\xF7\x7A\x77\x3C\xE2\x09\x71\x94\x43\x9B\x73\x49\xF9\xD4\xA5\x33\x0E\x98\x0D\xCC\x21\x15\x20\xE8\x6D\xC9\x82\xD6\xCF\x66\x93\xF7\x64\x55\xD5\xFB\x67\xC5\x0A\xE0\x3F\x1D\xDA\x3D\xDA\xA1\xCD\x70\x16\x60\xFF\x64\xAB\xC3\x02\xC1\x31\x0C\x6F\x65\x7E\x49\xEB\x77\xD5\x3F\x5F\x0E\xC6\xDE\x4F\x9F\x08\xD5\xC0\x81\x5D\xB0\x37\xCA\xA3\xA1\x1A\xD8\xD3\x0D\x5C\xC1\xC8\xF5\xBE\x82\x98\x19\x53\xD5\xFB\xE7\x45\x17\x30\x1F\x7B\x7F\xDD\x31\x52\x09\x6B\x3E\x85\xBD\x41\x2E\x08\xD5\xC0\x9E\xD1\x04\x47\x5B\xAE\xC1\x37\x48\xBA\xE9\xAC\x08\xDC\x15\x8E\x7D\x8B\xC0\xE3\x56\xCC\xB3\x42\x35\x30\xE6\x66\xEC\x0D\xF2\x8E\x50\x0D\x6C\x39\x86\xCE\xF5\xF7\x0A\xE2\x4E\x83\xB7\x2D\x25\x4F\xA7\xDF\x85\xBD\xBF\x16\x9B\x1B\x3D\x16\xFB\x95\xBD\x07\x43\x35\xB0\x65\x1C\xE9\x86\x08\x0B\x3B\xDC\x80\xED\x1E\x78\x37\xF0\x3D\xA3\xBE\x2D\xA6\xEC\x82\xE7\xF3\xB0\xF5\xD9\x57\x28\x34\x5F\x61\x5F\xEC\x9F\x66\x17\x46\x2A\x60\xCC\x6C\x6C\x6D\x61\x15\xC4\x96\xC1\xDB\x96\xE3\x0D\xFA\x95\x0B\x8F\x69\xF4\x5E\xA1\x1A\x18\xE1\x71\x5F\xEB\x01\xA1\x1A\xD8\x32\x17\x7B\x7B\x74\x3A\x9D\xB6\x9A\x36\x6F\x2C\x73",
				"\x3B\xE8\x53\x6E\x0E\xC2\xDE\x1E\x1F\x0F\xD5\xC0\x88\x1B\xB1\x35\xC2\x8B\xA4\xAC\xAE\x52\xB1\x9A\x3E\x5B\x05\xB1\x57\xF0\xF6\xB5\x74\x2D\x95\x31\xD8\x97\xDC\xB9\x21\x54\x03\x23\x9E\xC5\xD6\x08\xD7\xC7\x76\xDF\x1C\xCF\xBB\x8F\x47\x3A\x9D\xF6\x98\x36\xF7\x97\x35\x23\xE8\x4B\x15\xB1\x9E\x2D\x2D\x89\xED\x7E\xE7\x6C\x8D\xBD\x53\x9C\x1A\xAA\x81\x3D\x9E\x37\xE5\x8D\x24\x88\xBD\x83\xB7\x8F\xB4\x78\x59\x32\x67\x60\x6F\x93\x2D\x43\x35\xE8\x90\x3F\xC7\xDE\x00\x25\x6F\x1F\x81\xDF\x14\xBA\xBF\x0C\x35\x9D\xF6\x9C\x36\xF7\x97\x92\xA7\xD0\x00\xBB\x61\x6F\x93\x43\x3D\x3A\xEA\x95\x14\xB0\x9B\x71\x7B\xCB\x29\x3F\x2D\xED\x9E\x80\xBF\x71\x02\xF0\xEF\x0C\x3C\xAE\xDD\xAD\x7F\x3B\x21\xA0\x1F\x11\xBA\x7A\xF2\x08\xA9\x4C\xB1\x25\xD6\x31\x01\x94\x13\xC0\x77\x02\xEB\x8D\xDB\x8C\xE6\xBF\x82\xFE\xCE\x09\xA4\xF5\x82\xFE\xD3\xE9\x6E\xE0\x6A\x62\x82\x17\x7C\x0E\x06\x44\xD2\x07\xDC\x65\xDC\xA6\x4B\x00\x7B\x61\x5D\xA6\xE4\x4B\xB1\xDD\x77\xC1\x32\x91\x63\x38\xD2\x7E\x27\x8E\x78\xE7\xED\x2F\x8B\x29\x3B\x91\xA3\x8D\xF5\x7E\xB0\xF5\x03\xC1\x95\x95\xD8\x2A\x5F\x72\x7A\x5E\x7F\x2C\x52\x29\x47\x22\xD7\x10\xF3\xCE\x5B\xC7\xB1\x3A\x1E\x5B\xBB\x58\x4F\xC9\xDD\x98\x82\xBD\x53\xEC\x1C\xAA\x81\x2F\x9D\x1C\x66\xA8\xBA\x94\x7E\x98\xA1\x3F\xEF\xC0\xDE\x3E\x93\x43\x35\x18\x25\xFB\x60\xAB\xF4\x2A\xCA\x4E\xE0\xD8\x98\xA8\x95\xE0\x68\xF1\x3E\x29\x15\x4D\x0F\xF6\x7B\xF7\x7B\x5A\x77\xD2\xC3\xE0\x33\x8C\xDB\x5B\x48\xBA\x12\xB2\x2E\xAC\x07\x4E\x26\x39\x7C\x5D\x98\x03\x9C\x42\xF9\x0B\x8D\xFD\x59\x0B\x3C\x6D\xDC\xE6\x74\xE3\xF6\x5C\x02\x78\x7B\xE3\xF6\x16\x1B\xB7\x57\x05\xD6\x93\x1C\xBE\x0E\x41\x3C\x07\xF8\x08\xF5\x7A\xC8\xB6\xB1\xDE\xCF\xB6\xFE\x70\x73\x09\xE0\xAD\x8C\xDB\x5B\x64\xDC\x5E\x55\xA8\x43\x10\xD7\x39\x78\xC1\xFE\xC3\x63\x6B\xE3\xF6\x5C\x02\x78\xAA\x71\x7B\x8B\x8D\xDB\xAB\x12\x25\x07\x71\xDD\x83\x17\xEC\x3F\x3C\xCC\xEF\xAF\xF6\x08\x60\xEB\x4E\x3E\x6F\xDC\x5E\xD5\x28\x31\x88\x9B\x10\xBC\x00\xBF\x33\x6E\xAF\x91\x01\xBC\xD4\xB8\xBD\x2A\x52\x52\x10\x37\x25\x78\xC1\xDE\xF7\xAC\x67\xA7\x2E\x3C\x8E\xED\xD2\xFB\xBE\xB1\xDD\xCF\x4A\x74\xD6\xD4\x48\xE5\x06\xEA\xB5\xA5\x37\x14\x07\x60\x6B\xBF\x22\x2A\xAA\x3E\x83\xAD\xD2\xE6\x2B\x77\x15\xA7\xAA\x41\xDC\xB4\xE0\x85\x54\x12\xD6\xD2\x86\xD6\xDB\x52\x2E\xBC\x80\xAD\xD2\x45\x9D\xA3\x34\xA2\x6A\x41\xDC\xC4\xE0\x05\xFB\x73\xED\xD6\xEF\xD4\x2E\x2C\xC7\x56\xE9\x22\xD2\xCF\x1C\xA8\x4A\x10\x37\x35\x78\x21\xDD\xBF\x65\x69\xCB\x22\xAE\x03\xB2\xAE\x3C\x31\x21\xB6\xFB\x95\x22\x77\x10\x37\x39\x78\x01\xFE\x08\x5B\x7B\x16\x51\xA9\x64\x2D\xB6\x4A\x37\xD9\x81\x20\x5F\xEE\x74\xDD\x72\x9B\x47\xC3\x18\x6C\x6D\xBA\xD6\xBA\x83\x4D\x1F\xA0\x52\xE8\xCB\xF0\x37\xC7\x21\xFF\x68\x24\x9A\x42\xDB\x51\x85\x29\x74\x91\xB7\x0A\x18\xD1\xC8\x29\xB4\x16\xB1\x6C\xC8\x1D\xBC\x0A\xE2\x86\x2E\x62\x69\x1B\xA9\x73\xAA\x12\xBC\x4D\x0F\xE2\x46\x6E\x23\x29\x91\xA3\x33\xAA\x16\xBC\x4D\x0E\xE2\xCA\x27\x72\x78\x2C\x52\x58\xCF\xF3\x8B\xC8\x1F\x35\xA2\x5D\x3D\xF2\xC4\xDC\x1D\x19\x80\xD9\xC0\xF7\x69\x56\x10\x5B\xFB\x9E\xF9\x3B\xB0\x47\x00\xBF\x64\xDC\x9E\xF9\x09\x8E\x8A\x52\xE5\xE0\x6D\xD3\xB4\x20\xB6\xF6\x3D\xEB\xD8\x70\x09\x60\xEB\x13\x1C\x4D\x08\xE0\x12\x82\xB7\x4D\x93\x82\xB8\xF2\x27\xEB\x4A\x08\x60\xF3\x2A\x06\x15\xA3\xA4\xE0\x6D\xD3\x94\x20\xB6\xF6\xBD\x22\x02\xD8\x7A\x9A\x30\xDD\xB8\xBD\x2A\x51\x62\xF0\xB6\x69\x42\x10\x5B\x2F\xA0\x16\x31\x85\xB6\xAE\xA0\x31\xDD\xB8\xBD\xAA\x50\x72\xF0\xB6\xA9\x7B\x10\x4F\x37\x6E\xCF\x7C\x1B\xC9\x23\x80\x17\x1B\xB7\x37\xDD\xB8\xBD\x2A\x50\x87\xE0\x6D\x53\xE7\x20\xDE\xC1\xB8\xBD\x45\xC6\xED\xB9\xB0\x37\xB6\x7B\x67\xAB\xA9\xD7\x81\x06\x15\x76\x2F\x83\x1E\xE0\x35\x6C\x6D\xB4\x47\xA8\x06\xA3\x64\x0B\xEC\x9D\xE3\xED\xA1\x1A\xF8\xA2\xAB\x55\xCA\xE0\x9D\xD8\xDB\x67\x52\xA8\x06\x1D\xB0\x02\x5B\xC5\x8F\x8D\xED\xBE\x1B\xBA\xDC\xAC\x1C\x66\x63\x6B\x97\xA2\x8A\x33\xDE\x8B\xAD\xF2\x17\xC5\x76\xDF\x85\x1C\xD7\x8B\x8E\x41\xD7\x8B\x8E\x96\x4B\xB0\xB5\x8B\xCB\xF5\xA2\x5E\xEF\x2C\x0F\x1B\xB7\xB7\xB7\x71\x7B\x39\x38\x9A\xB8\xBC\xEE\xFE\xA5\x5F\xA3\x4B\xD6\x6E\x0F\x1C\x19\xF4\xB7\x3C\xB1\xF6\xB9\x87\x8C\xDB\x73\xE5\x5C\x6C\x9F\x5E\xCB\x28\x7F\x81\x64\x2E\x31\x9F\x80\x6F\xB6\x98\x14\xB9\x78\x36\xB7\x03\x3B\x55\x81\x6E\xEC\x5F\x03\x3F\x11\xAA\x41\x87\xCC\xC2\xDE\x29",
				"\x76\x0D\xD5\xC0\x9E\x88\xE9\xF3\x50\x2B\xC1\x51\x41\x6C\x7D\x29\x58\x34\xBB\x63\x6F\x93\x43\x22\x15\xE8\x94\x2D\xB1\x37\xC0\x69\xA1\x1A\xD8\x63\x7D\xD7\xEC\xC6\x32\xDC\x02\x74\x11\xEF\xC4\x6B\x46\x66\x9A\xCA\x71\x16\xF6\x36\x29\xEE\x54\x9D\xF5\xB9\xE0\x1B\x62\xBB\x6F\x8E\x75\xA9\xA1\xD1\x04\x6F\x1B\xEF\x20\x2E\xA2\x74\xCC\x20\xFC\x10\x5B\x7B\x2C\x0E\xED\xBD\x11\x73\xB0\x35\xC2\x52\xCA\x4E\xE8\xF0\x9A\x42\x8F\x36\x81\xC2\x73\x3A\x5D\xF2\x14\xBA\x07\xFB\xB2\x50\xD7\x7B\x75\xD6\x73\x61\xE8\x4E\xE3\xF6\xB6\x00\xF6\x33\x6E\x33\x92\x7B\x1C\xDA\xBC\x16\x38\x99\xB4\xD2\x3C\x52\xD6\xB7\xFE\xEF\xB5\xA6\x3D\x4A\x78\xE8\x1A\xC5\xBB\xB1\xAF\xC3\x76\x87\x71\x7B\x21\xEC\x83\xFD\x93\xBD\xE4\xFD\x60\xEB\xC4\x00\xAB\xA2\xEB\x1E\xD3\xE9\xE3\x0D\xFA\x95\x8B\x4B\xB1\xF7\xDB\x3D\x43\x35\x30\xA2\x07\x78\x05\x5B\x43\x58\xEF\x2F\x47\x62\x99\xC8\x61\x7D\x63\x82\x65\x10\x2F\xA6\xEC\x44\x8E\x47\xB1\xF5\xD9\x97\x29\xF8\xD5\xEF\x67\xD8\x3F\xCD\x4A\xDE\x4E\xB2\x48\xA5\xF4\x3A\x34\x60\xF5\x4E\x5C\x72\x2A\xE5\x1E\xD8\xFB\xEB\x8F\x43\x35\x30\xE6\x93\xD8\x1B\xE4\xC2\x48\x05\x1C\xE8\xE4\x30\x83\xF7\x89\x9F\x4E\x83\xB8\xF4\xC3\x0C\x1E\xD3\xE7\x33\x43\x35\x30\x66\x67\xEC\x0D\xF2\x58\xA8\x06\xF6\x74\x33\xBA\x20\xBE\x82\x98\x6C\xB4\xAA\xF7\xCF\x8B\x2E\x60\x01\xF6\xFE\x5A\x7C\x59\xE4\xF9\xD8\x1B\xE5\xA0\x50\x0D\x7C\x38\x06\x58\xC2\xD0\xBA\x2E\x21\xCF\xB4\xB4\xEA\xFD\xB3\xE6\x7D\xE8\xC3\x66\x40\xBE\x85\xBD\x61\xA2\x12\xF3\xBD\x19\x47\x5A\x9D\x9E\x43\x7A\xFA\xF7\xB6\x64\x41\xEB\x67\xB3\x5B\xBF\x93\x8B\xAA\xF7\xCF\x92\xEB\xB0\xF7\xD3\x6F\x86\x6A\xE0\xC4\xC1\xD8\x1B\x66\x35\xE9\xDE\x1A\x21\x2C\x98\x8C\x4F\xA6\x5C\x1D\x66\x8A\x74\x03\xBF\xC5\xDE\x38\xE7\x46\x2A\x21\x6A\xCD\xA7\xB1\xF7\xCF\x67\x28\x7B\x4D\xE0\xF7\xF0\x98\x46\x3F\x03\x8C\x8D\x54\x42\xD4\x92\xB1\xA4\x3B\x8B\xAC\xFD\xF3\x1F\x22\x95\xF0\x66\x26\xF6\x06\xEA\x23\xBD\x83\x09\xD1\x09\x1F\xC1\xC7\x37\xF7\x8F\x54\xC2\x9B\x6E\x7C\x9E\x72\x25\xE7\xDC\x8A\xFC\x74\x01\xF7\x63\xEF\x97\x4F\xB5\xDA\xAE\x15\x5F\xC4\xE7\x49\xF7\x97\x91\x4A\x88\x5A\x71\x24\x3E\x3E\xF9\xF9\x48\x25\xA2\x78\x2B\xB0\x16\x7B\x63\xDD\x47\x0D\x9F\x76\xC2\x9D\x2E\xE0\x01\xEC\xFD\xB1\x17\xD8\x26\x50\x8F\x50\x6E\xC2\xE7\x89\x77\x74\xA4\x12\xA2\x16\x1C\x8F\x8F\x2F\x16\x9D\xFB\x3C\x14\x1F\xC4\xC7\x68\x8F\xA1\x15\x69\x31\x7C\xC6\x01\x4F\xE2\xE3\x8B\x87\x07\xEA\x11\xCE\x18\x7C\xF2\x4D\xFB\x80\x4F\x05\xEA\x21\xCA\xE6\xB3\xF8\xF8\xE0\x42\x0A\x3E\x3A\x38\x5C\x3C\x4E\x28\xF5\x91\x4A\xCF\x16\x57\x38\x4C\x84\x33\x0D\xFB\x92\xB1\x6D\x39\x3B\x50\x8F\x6C\x6C\x46\x0A\x36\x0F\x03\x5E\x19\xA8\x87\x28\x93\xEF\xE2\xE3\x7B\x2F\x01\x9B\x06\xEA\x91\x95\xAF\xE0\x63\xC4\x75\xA4\xA4\x11\x21\x06\xE2\x60\x52\x2D\x30\x0F\xDF\x2B\xB9\xDC\xD3\x88\xD9\x06\xBF\x3A\xC9\x8F\x51\x76\x49\x17\xE1\xC3\x04\xFC\x16\xAE\x56\x01\x5B\xC5\xA9\x52\x0D\xFE\x11\x1F\x63\xF6\x01\x17\x07\xEA\x21\xCA\xC0\x6B\xD6\xD7\x07\x7C\x2D\x50\x8F\xCA\xB0\x25\xF6\x45\xEF\xDA\xD2\x4B\x2A\x0F\x2A\x04\xA4\x63\x7D\x1E\x49\x44\x7D\x24\x1F\x9E\x16\xA7\x4A\xB5\xF8\x2A\x7E\x4F\xC5\xA7\x80\x3F\x8E\x53\x45\x54\x94\x49\xC0\x22\xFC\xFC\xEC\x92\x38\x55\xAA\xC7\x14\xFC\x96\xF4\xFB\x48\xA5\x52\x45\xB3\xB9\x1E\x3F\xFF\x5A\x8E\x0A\x4B\xF0\x19\xFC\x0C\xDC\x07\x9C\x1A\xA7\x8A\xA8\x18\x67\xE0\xEB\x5B\x4A\x1E\x22\xA5\xB5\x3D\x81\x9F\x91\xD7\x50\xF6\x95\x2C\x62\x74\x1C\x00\xBC\x86\x9F\x5F\x29\x7D\xB7\x1F\x47\xE0\xFB\xA4\x5C\x8C\xB2\xB4\x9A\xC4\x34\xEC\x6F\xC7\xDC\x58\x0E\x0B\xD3\xA6\x10\x6E\xC1\xD7\xE0\xBF\x40\xFB\xC3\x4D\x60\x02\xE9\x62\x3D\x4F\x5F\xFA\x69\x98\x36\x05\xB1\x33\xBE\x77\xE8\xF6\x01\x73\xD1\xD9\xE1\x3A\xD3\x85\xEF\xA2\x55\x1F\x29\x69\x63\xC7\x28\x85\x4A\xE3\x7C\x7C\x8D\xDF\x47\xBA\x3E\x43\xD4\x93\xAF\xE3\xEF\x3F\x9F\x0E\xD3\xA6\x40\x7A\x48\x15\x36\xBC\x07\xE1\x73\x51\x0A\x89\x30\xCE\xC5\xDF\x6F\x1E\x40\x0B\x57\x43\xB2\x0F\x29\x93\xCA\x73\x20\xD6\x93\xB6\x18\x44\x3D\xF8\x38\xFE\xC1\xDB\x0B\xEC\x15\xA5\x50\xE9\x5C\x88\xFF\x80\xAC\x03\x4E\x8A\x51\x47\x38\x72\x2A\x7E\x27\x8C\xFA\xCB\x05\x51\x0A\xD5\x81\x1E\xFC\x57\x12\xDB\x9F\xC4\xDA\x8C\x2F\x97\x33\x48\x0F\x62\x6F\x3F\xB9\x9D\x06\x54\xDA\xB0\x66\x07\xD2\xED\xE6\xDE\x83\xD3\x07\xFC\x7D\x90\x4E\xC2\x8E\x88\x05\xCF\x3E\x52\xAA\xEF\xF4\x18\x95\xEA\xC7\x89\xC4\x0C\x52\x1F",
				"\xE9\xB8\x99\xB6\x98\xAA\x4F\x37\x31\xAB\xCD\x6D\xF9\x70\x8C\x5A\xF5\xE5\x5F\x89\x1B\xAC\x1F\x91\x12\x01\x44\x35\x19\x0F\xFC\x80\x38\x7F\xF8\x4E\x8C\x5A\xF5\x66\x13\xD2\x15\x2A\x51\x83\xF6\x4B\x94\x76\x59\x45\xA6\x11\xB3\x2E\xD2\x96\x5F\xA3\xCC\x3D\x33\xB6\x03\x5E\x20\x6E\xF0\x9E\x21\x25\xC3\x8B\x6A\xB0\x0F\xBE\x67\x7A\x37\x96\xE7\x49\x37\x89\x08\x43\x66\xE1\xBF\x3F\xDC\x5F\xD6\xA0\xA3\x88\x55\xE0\x63\xF8\x9E\x2A\xDA\x58\xDE\x00\x0E\x89\x50\xAC\x89\x9C\x4E\xDC\x40\xB6\xE5\x1A\x54\xD9\x23\x07\x93\xF0\xCF\x6B\x1E\x48\x4E\x89\x50\xAE\xC9\x5C\x46\xFC\xA0\x2E\x46\xE5\x6A\x23\x39\x00\xBF\x1B\x3C\x06\x93\x46\x95\x86\xCD\x45\x17\x30\x87\xF8\xC1\xED\x25\x55\xBB\xD4\xC2\x86\x1F\x9B\x00\x5F\xC6\xAF\x00\xDD\x60\x72\x1D\xDA\x46\x0C\x63\x13\xE0\xE7\xC4\x0F\x72\x1F\xA9\x12\xC3\x7B\xFC\x55\x6C\x1C\x87\xE0\x5B\x99\x65\x30\xB9\x05\x3D\x98\xC3\xD9\x8C\xD8\x6D\x85\xFE\xB2\x1E\xF8\x17\x52\x69\x5C\xD1\x19\xD3\x48\xD7\x9D\x44\xE4\x33\x0F\x24\xB7\xD3\xA0\x2B\x51\xAA\xC6\x24\x62\xF7\x88\x37\x96\xE5\xA4\x94\x3E\x3D\xBD\x47\xCE\x58\x52\x1E\xBA\x67\x55\xD2\xA1\xE4\x01\x54\x55\x32\x3B\x53\x81\x87\xC9\xE7\x04\x7D\xC0\xE3\xC0\x87\xD0\x3B\xD4\x70\xE8\x06\x8E\xC3\xEF\x9A\x93\xE1\xCA\xC3\x28\x61\xA7\x32\x6C\x0E\xDC\x45\x5E\x87\x68\x3B\x85\x02\xF9\xCD\x99\x45\x4C\xC1\x86\xA1\xE4\x3E\x14\xBC\x95\x63\x32\x70\x07\xF9\x9D\xA3\xED\x20\x7F\x45\x3A\x16\xD9\x74\xC6\x02\x7F\x0D\xDC\x4F\xFE\x71\xE9\x23\xA5\xCA\x4E\x72\xD5\x58\x8C\x9A\xCD\x80\x5B\xC9\xEF\x24\x6D\x79\x1A\x38\x8F\x66\xBE\x67\x6D\x4E\x2A\xDA\xBF\x84\xFC\xE3\xD0\x96\x5B\xD0\x82\x55\xE5\x19\x4F\xDA\xD3\xCB\xED\x2C\xFD\xE5\x35\xE0\x46\xD2\x14\xB2\xEE\xD3\xEB\x7D\x80\xAB\x48\xD5\x1B\x73\xDB\xBD\xBF\xDC\x48\xDA\x7E\x14\x05\xD0\x85\xEF\x75\x92\x9D\xC8\x93\xA4\x84\x90\x77\xB9\x69\x1F\xCF\xEE\xA4\x4B\xBE\x72\x64\x4F\x0D\x47\x2E\xA6\xFE\x0F\xCE\x5A\x72\x1A\xB1\x07\x20\x46\x2A\xF3\x48\x8E\x7F\x10\x65\x95\x6C\xE9\x21\xA5\x96\x5E\x4A\x4A\x6C\xC9\x6D\xC7\x37\x93\x37\x80\x93\x9D\x6C\x20\x82\x38\x94\xD8\xA3\x88\xA3\x95\x65\xA4\xC2\xF3\x67\x90\x3E\x9D\xBB\x3D\x8C\x31\x4A\xBA\x81\xDD\x80\x33\x81\x1F\x92\xF6\xBF\x73\xDB\x6B\x28\x79\x9E\x06\x9C\x2A\x6A\xCA\xB4\xE2\x6D\xA4\x6A\x1B\x25\x5D\x72\xB6\x82\x94\x69\x76\x3F\xF0\x10\x69\x8B\x6A\x3E\x29\x4F\xD8\x93\x1E\x60\x17\x52\xC0\xEE\x4E\x2A\xA5\x7A\x20\x65\xAD\xDC\xDE\x05\x1C\x0B\x3C\x9B\xBB\x23\xDE\x34\x25\x80\x21\x2D\x60\xFC\x13\xF0\xD1\xDC\x1D\xE9\x80\xD7\x81\x85\xA4\xD3\x51\x8B\x5A\xF2\x3C\xB0\xB4\x9F\xBC\x4C\x0A\xF2\xB5\xA4\xDB\xE3\x01\x26\x92\x02\xB3\x87\x14\x88\x53\xFA\xC9\x56\xC0\x8C\x8D\xA4\xE4\xCC\xB2\x2B\x81\x73\x48\xB6\x12\x35\xE4\x04\xE2\xAA\x5D\x4A\xE2\x64\x05\x2A\x40\xD7\x18\xB6\x27\xDD\x56\x98\xDB\xE9\x24\x36\xF2\x2B\x74\xE1\x58\xE3\xE8\x21\xDD\x00\x51\xE5\x55\x6A\xC9\xE0\xD2\x4B\xAA\xE9\x5D\xD2\x0A\xBE\x30\x66\x0F\xE0\x6E\xF2\x3B\xA3\x64\x64\xF2\x00\xB0\xEF\x00\xE3\x29\x1A\x48\x0F\xE9\x68\xDB\xAB\xE4\x77\x4C\xC9\xE0\xB2\x9A\x74\x84\x53\x9F\xBA\xE2\x0F\xD8\x09\xB8\x99\xFC\x4E\x2A\x19\x58\x6E\x22\x5D\xB9\x23\xC4\xA0\xCC\x02\x1E\x21\xBF\xC3\x4A\x92\x3C\x01\x7C\x60\xD0\x11\x13\x62\x23\xC6\x91\x6E\x63\xCF\x59\x31\xA2\xE9\xB2\x8C\xB4\xA7\xAB\x4B\xB5\xC5\xA8\xD9\x82\xB4\x5A\xAD\xBD\xE3\x38\x79\x95\x54\x3E\xB8\x89\xC7\x30\x85\x13\x53\x49\x4E\x55\xB5\x63\x72\x75\x92\x55\xC0\x15\xC0\xD6\xC3\x1C\x13\x21\x46\xCC\xD6\xA4\x53\x38\x4B\xC9\xEF\xF0\x75\x91\x97\x48\xA7\xB2\xB6\x1A\xC1\x38\x08\xD1\x11\x9B\x92\xAE\x7A\x79\x9C\xFC\x01\x50\xAA\x2C\x24\x6D\xDF\xA9\x4A\x86\xC8\xC6\x18\xE0\x08\xE0\x27\xE4\xB9\x51\xA0\x34\xE9\x05\x7E\x0C\x1C\x8E\xF6\x72\x45\xC5\xD8\x16\xF8\x02\xE9\x93\x25\x77\xA0\x54\x4D\x16\x00\x9F\x07\xB6\x19\xB5\x75\x85\x08\xE4\x9D\xA4\xD5\xEB\x26\x07\xF3\xB3\xA4\x45\xA9\x99\x34\xEB\xE8\xAA\xA8\x11\xDD\xC0\x7B\x81\xCB\xC9\x77\xF7\x4F\xA4\x3C\x0E\x7C\x93\x14\xB4\x55\xAA\x2A\x22\x84\x09\x3B\x00\x67\x91\xDE\x99\x57\x92\x3F\xE0\x3A\x95\x97\x81\xFF\x26\x95\xDB\x99\x61\x68\x27\x31\x0C\x34\xAD\xC9\xCB\x18\x52\xE9\x9A\x99\xA4\xB2\x35\x33\x81\xED\xB2\xF6\x68\x68\x9E\x21\x15\x47\xBF\x93\x74\x31\xD8\x23\xC0\xBA\xAC\x3D\x6A\x30\x0A\xE0\xEA\x31\x95\x54\x8B\x6A\x37\x36\xD4\xA5\xDA\x89\xF8\xAC\xA4\x65\xA4\x85\xA7\x76\x3D\xAE\x47\x80\x07\x49\xFB\xDF\xA2\x22\x28\x80\xCB\x61\x12\x69",
				"\x8A\x3A\xBD\x25\x6F\x21\x05\x7B\xFF\xFA\x56\xE3\x5B\xBF\xD7\x4D\xCA\x1F\xDE\xAC\xF5\x7F\x5F\x25\x6D\xDF\xAC\x27\x4D\x79\x5F\x27\x05\xE2\x4B\xAD\xAF\x2F\x02\xBF\x23\xDD\x24\xB1\xA8\x25\x2B\xDD\x35\x12\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x08\x21\x84\x10\x42\x14\xCF\xFF\x03\xB1\x8E\xCD\xDE\x86\xA6\xFE\xA6\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x46\x69\x6C\x65\x83\x0A\x00\x00\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\xF0\x00\x00\x00\xF0\x08\x06\x00\x00\x00\x3E\x55\xE9\x92\x00\x00\x00\x06\x62\x4B\x47\x44\x00\xFF\x00\xFF\x00\xFF\xA0\xBD\xA7\x93\x00\x00\x0A\x38\x49\x44\x41\x54\x78\x9C\xED\xDD\x4B\xAC\x5D\x55\x1D\xC7\xF1\x6F\xB1\x5C\x0A\xAD\x60\x62\xD2\x52\x1E\x36\xEA\xA0\x32\xD1\x28\x30\x30\x10\x30\xC1\x47\x9C\xF5\x01\xA6\x13\x67\x0C\x14\x22\xC1\x10\x26\x24\xA2\x71\x0A\x9A\xA0\x4E\x1C\x69\x2B\xC2\x45\x12\x0A\x92\x18\x1F\x09\xB4\x3C\xA2\x09\x15\x13\x62\x10\xB5\x26\x4A\x54\xA8\x46\x45\x21\x69\x69\xAF\xAD\x83\x7D\x6E\x72\xC1\xAB\x9C\x7B\xF7\xDA\xEB\xBF\xFE\x7B\x7F\x3F\xC9\x7F\xBA\xEF\x7F\xAF\xB5\x7E\x77\x9F\xB3\xCF\x7E\x80\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x14\x6B\x43\x74\x03\x81\x36\x03\x57\x03\x97\x03\x3B\x67\xB5\x0D\xB8\x00\xD8\x02\x9C\x1D\xD7\x5A\xF3\x4E\x01\x2F\x01\x8F\x00\x77\x00\xAF\xC5\xB6\xA3\xA9\xD8\x06\xDC\x0A\x3C\x01\xBC\x0E\x9C\xB1\x7A\xD7\x12\x70\xD7\x5A\x26\x41\x5A\xAB\x8F\x00\x8F\xD2\x1D\x39\xA2\x17\xFC\x58\xEB\xE7\xC0\xC6\x39\xE7\x43\x9A\xCB\x75\xC0\xD3\xC4\x2F\xEE\xA9\xD4\xF3\xC0\x59\x73\xCD\x8C\xF4\x7F\x6C\x07\x0E\x10\xBF\xA0\xA7\x58\x4F\xE1\x91\x58\x3D\xEC\x03\x5E\x21\x7E\x21\x4F\xB9\xEE\xC5\x23\xB1\xD6\x68\x13\xF0\x4D\xE2\x17\xAF\xD5\xD5\x7E\x0C\xB1\xE6\xB4\x05\xF8\x31\xF1\x8B\xD6\x7A\x63\xDD\x8F\x1F\xA7\xF5\x16\xB6\x01\xCF\x12\xBF\x58\xAD\xD5\xCB\x23\xB1\xFE\xA7\xF3\x31\xBC\x19\xCA\x23\xB1\xFE\xCB\x26\xE0\x30\xF1\x8B\xD3\x9A\xAF\x3C\x12\xEB\x0D\x3C\x61\x95\xAF\x3C\x12\x0B\x80\x1B\x88\x5F\x8C\x96\x21\xD6\x3A\x5C\x84\xBF\xF3\x66\x2F\x3F\x4E\x4F\xD8\x22\xF1\x0B\xD0\xEA\x5F\x1E\x89\x27\xE8\x3A\xE2\x17\x9E\x55\xAE\x3C\x12\x4F\xCC\x93\xC4\x2F\x3A\xAB\x6C\x79\x24\x9E\x88\x6B\x89\x5F\x6C\xD6\x30\xE5\x91\x78\x02\x1E\x25\x7E\xA1\x59\x86\xB8\x29\x59\x1E\xA9\xB3\x15\xF8\x13\x7E\xD4\x1A\xBB\x45\xE0\xD3\x74\x4F\xF9\xD0\x88\x7C\x9E\x61\xFF\xFB\x9F\xA0\xBB\x7F\x78\x37\xB0\x83\x69\x3E\x0F\x2B\xFA\x08\xEC\x91\x78\xC4\x9E\x60\xB8\x05\x73\x1F\xDD\x6F\xCB\x53\x17\x1D\x5C\x43\x3C\x52\x9B\x19\xE6\x01\x74\x4B\xC0\x67\x2A\xEE\x47\xEB\xA2\x43\x6B\x88\x47\xEA\x13\x0C\xB3\x40\x3E\x5B\x73\x27\x12\x88\x0E\xAC\x21\x1E\xA9\x3B\x28\xBF\x30\xEE\xAB\xBA\x07\x39\x44\x87\xD5\x10\x8F\xD4\x7E\xCA\x2E\x88\xE3\xF8\x9D\x77\x35\xD1\x41\x35\xC4\x23\xF5\x33\xCA\x2E\x86\x03\x75\xDB\x4F\x23\x3A\xA4\x86\x78\xA4\x7E\x4F\xD9\x85\xB0\xBB\x6A\xF7\x79\x44\x07\xD4\x10\x8F\xD4\xDF\x28\xBB\x08\xDE\x55\xB7\xFD\x34\xA2\xC3\x39\x6F\x79\xED\x74\x32\xA5\x7F\x42\x9A\xE2\x45\x1A\xF3\x88\x0E\xA6\x21\x1E\xA9\xD2\x93\xAF\xD5\x45\x87\xD2\x10\x8F\x94\x01\xAE\x23\x3A\x90\x86\x78\xA4\x0C\x70\x1D\xD1\x61\x34\xC4\x23\x65\x80\xEB\x88\x0E\xA2\x21\x1E\x29\x03\x5C\x47\xE9\x71\xFE\xF6\x00\xDB\x34\xC4\x09\x19\xE0\x3A\x4A\x8F\xF3\x59\x18\x62\x61\x80\x6B\x19\x62\x9C\x0D\xB1\x0C\x70\x25\x43\x8D\xB3\x21\x9E\x38\x03\x5C\xC7\x90\xE3\x6C\x88\x27\xCC\x00\xD7\x31\xF4\x38\x1B\xE2\x89\x32\xC0\x75\xD4\x18\x67\x43\x3C\x41\x06\xB8\x8E\x5A\xE3\x6C\x88\x27\xC6\x00\xD7\x51\x73\x9C\x0D\xF1\x84\x18\xE0\x3A\x6A\x8F\xB3\x21\x9E\x08\x03\x5C\x47\xC4\x38\x1B\xE2\x09\x30\xC0\x75\x44\x8D\xB3\x21\x1E\x39\x03\x5C\x47\xE4\x38\x1B\xE2\x11\x33\xC0\x75\x44\x8F\xB3\x21\x1E\xA9\xE8\x85\x35\x15\x2D\x8C\xB3\x21\x1E\xA1\x16\x16\xD6\x14\xB4\x32\xCE\x86\x78\x64\x5A\x59\x58\x63\xF7\x2F\xEA\x86\xA6\xB5\x7A\x80\x84\x21\xF6\x19\xBB\x5A\xF6\x52\x74\x03\xC1\x3E\x05\x1C\x22\x59\x88\x0D\xB0\x96\x4D\x3D\xC0\x00\x57\x01\xCF\x91\x28\xC4\x06\x58\xCB\xFE\x1C\xDD\x40\x23\x2E\x03\x8E\x44\x37\x31\x2F\x03\xAC\x65\x69\x16",
				"\x6D\x05\x1F\x00\xEE\x8A\x6E\x62\x1E\x1B\xA2\x1B\x98\x43\xE9\x13\x4F\x19\xF6\x39\xC2\x7B\x81\xA3\xD1\x4D\x34\x64\x09\x78\x27\xDD\xC9\xBD\x66\x79\x04\xD6\xB2\xDF\x01\xBF\x8C\x6E\xA2\x21\x1B\x81\x2F\x47\x37\xF1\x56\x0C\xB0\x56\x3A\x18\xDD\x40\x63\xF6\x44\x37\xF0\x56\x32\x7C\x9C\xF4\x23\x74\x3D\xDB\xE8\x3E\x46\x6F\x89\x6E\xA4\x11\x4B\x34\xFE\x32\x3C\x8F\xC0\x5A\xE9\x18\x70\x77\x74\x13\x0D\x69\xFE\xE7\xA4\x0C\x47\x23\x8F\xC0\x75\x6D\x01\x7E\x0B\x5C\x18\xDD\x48\x23\x9A\x5E\x2F\x1E\x81\xF5\x66\xAF\x01\x37\xE1\x65\xA7\x29\x18\x60\xAD\xE6\x20\xF0\xA5\xE8\x26\x34\x0E\xDE\xCC\x10\x63\x03\xDD\x5D\x3A\xD1\x37\x19\x44\x97\x7A\x72\x42\xE2\x9C\x0B\x3C\x48\x7C\x88\x0C\x70\x62\x4E\x48\xAC\x0D\xC0\x9D\xC0\x69\xE2\xC3\x64\x80\x13\x72\x42\xDA\xB0\x9B\xEE\x86\x87\xE8\x40\x19\xE0\x64\x9C\x90\x76\x6C\x06\xBE\xC0\xB4\x6E\xFE\x6F\x5A\xD3\xBF\x71\xCD\x94\x1E\xC4\x0C\xFB\xDC\xBA\xAD\xC0\xCD\xC0\x2E\xE0\xFD\xC1\xBD\x0C\xAD\xE9\xF5\xD2\x74\x73\x33\x06\xB8\x6D\xEF\xA1\x0B\xF2\x07\x81\x8B\x81\xED\xC0\x25\x8C\xE7\x72\xCC\xA6\xD7\x4B\xD3\xCD\xCD\x18\x60\xAD\xC5\xA4\xD6\x8B\x17\x72\x48\x89\x19\x60\x29\x31\x03\x2C\x25\x66\x80\xA5\xC4\x0C\xB0\x94\x98\x01\x96\x12\x33\xC0\x52\x62\x06\x58\x4A\xCC\x00\x4B\x89\x19\x60\x29\x31\x03\x2C\x25\x66\x80\xA5\xC4\x0C\xB0\x94\x98\x01\x96\x12\x33\xC0\x52\x62\x06\x58\x4A\xCC\x00\x4B\x89\x19\x60\x29\x31\x03\x2C\x25\x66\x80\xA5\xC4\x0C\xB0\x94\x98\x01\x96\x12\x33\xC0\x52\x62\x06\x58\x4A\xCC\x00\x4B\x89\x19\x60\x29\x31\x03\x2C\x25\x66\x80\xA5\xC4\x0C\xB0\x94\x98\x01\x1E\xC6\x02\xB0\x0F\x58\x04\x8E\x02\xA7\x88\x7F\x51\x75\xED\x3A\x35\xDB\xF7\xC5\xD9\x58\x2C\xF4\x1A\x51\xA5\x95\xED\x8D\xEB\x7B\x81\x17\x07\xE8\x3B\x7B\xBD\x38\x1B\x9B\xA1\x65\x5B\x2F\xA3\x97\x65\x42\xCE\x02\xEE\x19\xA0\xDF\xB1\xD5\x3D\x0C\xFB\xC9\x2F\xCB\x7A\x99\x8C\x2C\x13\x62\x78\xD7\x16\xE2\xA1\x64\x59\x2F\x93\x91\x61\x42\xF6\x0E\xD0\xE7\xD8\x6B\xA8\x8F\xD3\x19\xD6\x4B\x31\x1B\xA2\x1B\x98\x43\xE9\x41\x2C\xBD\xCF\x0B\xC0\x0B\xC0\xBB\x0B\x6F\x77\xEC\xFE\x00\xEC\x04\x5E\x2F\xBC\xDD\xD6\xD7\x4B\x51\x9E\x85\xEE\x6F\x0F\x86\x77\x3D\x76\x00\xBB\xA2\x9B\xC8\xCE\x00\xF7\xB7\x3B\xBA\x81\xC4\xF6\x44\x37\x90\x9D\x01\xEE\xEF\xCA\xE8\x06\x12\x73\xEC\x7A\x6A\xFA\xF3\xFD\x4C\xEB\xDF\x69\x8E\x03\x9B\x0A\x6F\x73\x2A\x4E\x00\xE7\x16\xDE\x66\xEB\xEB\xA5\x28\x8F\xC0\xFD\x35\x7F\xA6\xB2\x61\xA7\xA3\x1B\xC8\xCE\x00\xF7\xF7\x72\x74\x03\x89\x1D\x8B\x6E\x20\x3B\x03\xDC\xDF\x33\xD1\x0D\x24\xE6\xD8\xF5\x64\x80\xFB\x3B\x18\xDD\x40\x62\x0F\x45\x37\x90\x5D\xD3\x5F\xD0\x67\x5A\x3F\x29\xE1\x85\x1C\xEB\xE3\x85\x1C\x05\x78\x04\xEE\xEF\x24\x70\x7B\x74\x13\x09\xDD\x46\xF9\xF0\xAA\x41\x59\xAE\x6D\xF5\x66\x86\xF9\xCB\x9B\x19\x26\x24\xCB\x84\x78\x3B\xE1\xFC\xE1\xF5\x76\xC2\x09\xC9\x36\x21\xDE\xD0\xBF\x7A\x79\x43\xFF\x00\x9A\xFE\x82\x3E\x53\x7A\x10\x6B\xEC\xF3\x02\xDD\x75\xBE\xBB\x80\x2B\xE8\x2E\xDC\xDF\x58\xE1\xEF\xB6\x64\x89\xEE\x44\xD5\x11\xE0\x61\xBA\x33\xCE\x27\x2B\xFC\xDD\x8C\xEB\x65\xDD\x9A\x6E\x6E\x66\x52\x13\xA2\xDE\x26\xB5\x5E\x3C\x0B\x2D\x25\x66\x80\xA5\xC4\x0C\xB0\x94\x98\x01\x96\x12\x33\xC0\x52\x62\x06\x58\x4A\xCC\x00\x4B\x89\x19\x60\x29\x31\x03\x2C\x25\x66\x80\xA5\xC4\x0C\xB0\x94\x98\x01\x96\x12\x33\xC0\x52\x62\x06\x58\x4A\xCC\x00\x4B\x89\x19\x60\x29\x31\x03\x2C\x25\x66\x80\xA5\xC4\x0C\xB0\x94\x98\x01\x1E\xC6\x02\xB0\x0F\x58\x04\x8E\x02\xA7\x88\x7F\x2A\x64\xED\x3A\x35\xDB\xF7\xC5\xD9\x58\x2C\xF4\x1A\x51\xA5\x95\xED\x31\xA1\x3E\x56\x76\xF5\xF2\xB1\xB2\x13\x95\x65\x42\x7C\xB0\xFB\x7C\xE5\x83\xDD\x27\x26\xCB\x84\x18\xDE\xB5\x85\x78\x28\x59\xD6\xCB\x64\x64\x98\x90\xBD\x03\xF4\x39\xF6\x1A\xEA\xE3\x74\x86\xF5\x52\x4C\xD3\x0F\xAD\x9E\x29\x3D\x88\xBE\x5E\xB4\x0D\xBE\x5E\xB4\x00\xCF\x42\xF7\xB7\x07\xC3\xBB\x1E\x3B\xE8\x5E\x3D\xA3\x1E\x0C\x70\x7F\xBB\xA3\x1B\x48\x6C\x4F\x74\x03\xD9\x19\xE0\xFE\xAE\x8C\x6E\x20\x31\xC7\xAE\xA7\xA6\x3F\xDF\xCF\xB4\xFE\x9D\xE6\x38\xB0\xA9\xF0\x36\xA7\xE2\x04\x70\x6E\xE1\x6D\xB6\xBE\x5E\x8A\xF2\x08\xDC\x5F\xF3\x67\x2A\x1B\x76\x3A\xBA\x81\xEC\x0C\x70\x7F\x2F\x47\x37\x90\xD8\xB1\xE8\x06\xB2\x33\xC0\xFD\x3D\x13\xDD\x40\x62\x8E\x5D\x4F\x06\xB8\xBF\x83\xD1\x0D\x24\xF6\x50\x74\x03\xD9\x35\xFD\x05\x7D\xA6\xF5\x93\x12\x5E\xC8\xB1\x3E\x5E\xC8\x51\x80\x47\xE0\xFE\x4E\x02\xB7\x47",
				"\x37\x91\xD0\x6D\x94\x0F\xAF\x1A\x94\xE5\xDA\x56\x6F\x66\x98\xBF\xBC\x99\x61\x42\xB2\x4C\x88\xB7\x13\xCE\x1F\x5E\x6F\x27\x9C\x90\x6C\x13\xE2\x0D\xFD\xAB\x97\x37\xF4\x0F\xA0\xE9\x2F\xE8\x33\xA5\x07\xB1\xC6\x3E\x2F\xD0\x5D\xE7\xBB\x0B\xB8\x82\xEE\xC2\xFD\x8D\x15\xFE\x6E\x4B\x96\xE8\x4E\x54\x1D\x01\x1E\xA6\x3B\xE3\x7C\xB2\xC2\xDF\xCD\xB8\x5E\xD6\xAD\xE9\xE6\x66\x26\x35\x21\xEA\x6D\x52\xEB\xC5\xB3\xD0\x52\x62\x06\x58\x4A\xCC\x00\x4B\x89\x19\x60\x29\x31\x03\x2C\x25\x66\x80\xA5\xC4\x0C\xB0\x94\x98\x01\x96\x12\x33\xC0\x52\x62\x19\x02\x5C\xFA\xF2\x3B\xDF\x92\x37\x5E\xA5\xE7\xB6\xF9\xDB\x1D\x33\x04\xF8\xB5\xC2\xDB\xDB\x5E\x78\x7B\x6A\xC7\x45\x85\xB7\xF7\x6A\xE1\xED\x15\x37\xC5\x00\x5F\x5E\x78\x7B\x6A\x47\xE9\xE7\x4C\x1B\xE0\x02\x5E\x2A\xBC\x3D\xDF\xA4\x30\x5E\xA5\x5F\xD5\xE2\x13\x47\x0B\xD8\x4F\xD9\xFB\x3B\x4F\x00\x17\x57\xDD\x03\xD5\x70\x29\xDD\xDC\x96\x5C\x2B\xDF\xAA\xBA\x07\xEB\x90\xE1\x08\xFC\xEB\xC2\xDB\x3B\x07\xF8\x4A\xE1\x6D\x2A\xDE\x57\xE9\xE6\xB6\xA4\xD2\x6B\x6F\x92\x3E\xCE\x30\x4F\x88\xB8\xA9\xE6\x4E\x68\x50\xB7\x30\xCC\x1A\xF9\x68\xCD\x9D\x18\xAB\xF3\xE8\x4E\xE7\x97\x9E\x9C\x25\xE0\xE6\x8A\xFB\xA1\x61\xDC\x02\xFC\x9B\xF2\xEB\x63\x88\xF7\x36\x4D\xD6\x61\x86\xF9\x0F\x7B\x06\x78\x00\xB8\xA4\xDE\xAE\xA8\x90\x4B\x81\x07\x19\x6E\x5D\x3C\x5E\x6F\x57\xC6\xEF\x56\x86\x9B\xA8\xE5\xFF\xB6\xDF\x01\xAE\xA7\x7B\x40\xBB\x17\x7B\xB4\x67\x81\x6E\x6E\x6E\x00\xBE\x4B\xF9\x13\x56\x6F\xAE\xCF\xD5\xD9\xAD\x7E\x9A\x7E\xDE\xCF\x0A\x5B\x81\x3F\x02\x67\x47\x37\xA2\x49\x58\xA2\xFB\x54\xD6\xFC\xCB\xD7\x32\x9C\x85\x06\xF8\x0B\xF0\xC3\xE8\x26\x34\x19\x3F\x20\x41\x78\x21\x4F\x80\xC1\x9F\x7E\x54\xCF\xDD\xD1\x0D\xCC\x2B\x53\x80\x0F\x03\x4F\x45\x37\xA1\xD1\x3B\x04\x3C\x19\xDD\xC4\xBC\x32\x05\x18\xE0\xCE\xE8\x06\x34\x6A\x67\x80\x2F\x46\x37\xB1\x16\xD9\x02\xFC\x38\x70\x7F\x74\x13\x1A\xAD\x7B\x81\x27\xA2\x9B\x58\x8B\x2C\x67\xA1\x57\xDA\x0E\xFC\x0A\xB8\x20\xBA\x11\x8D\xCA\x3F\x80\xCB\x48\x72\xF2\x6A\x59\xB6\x23\x30\x74\x77\x27\xDD\x18\xDD\x84\x46\xE7\x46\x92\x85\x17\xE0\x6D\xD1\x0D\xAC\xD3\xF3\xC0\x36\xCA\xDF\xFF\xA9\x69\xFA\x3A\xDD\xCD\x10\xAA\xE8\x1C\xE0\x31\x86\xBD\x1A\xC7\x1A\x7F\xFD\x84\xC4\x57\xDE\x65\xFC\x0E\xBC\xD2\xDB\xE9\x4E\xFB\x7F\x28\xB8\x0F\xE5\xF4\x1C\x70\x0D\xF0\xCF\xE8\x46\xD6\x2B\xE3\x77\xE0\x95\x5E\x05\x3E\x09\xFC\x22\xBA\x11\xA5\xF3\x2C\xF0\x31\x12\x87\x77\x4C\xB6\x00\x3F\x22\xFE\xE3\x98\x95\xA3\x1E\x03\xCE\x47\x4D\x39\x07\xF8\x06\xF1\x8B\xC3\x6A\xBB\xBE\x46\xE2\xEF\xBC\x53\x70\x3D\xDD\x6F\x7A\xD1\x0B\xC5\x6A\xAB\xFE\x0E\xEC\x41\x29\x5C\x08\x1C\x00\x4E\x13\xBF\x70\xAC\xF8\xFA\x1E\xDD\xCF\x8E\x4A\xE6\x5A\x86\x7D\x9A\x87\xD5\x76\x1D\xA2\x3B\xCB\xAC\xE4\xAE\x01\xBE\x4F\xF7\x9A\x96\xE8\x45\x65\x0D\x5B\x27\x81\x47\x80\xAB\x99\x80\xEC\xBF\x03\xAF\xD5\x56\x60\x1F\xDD\xC3\xDD\x3F\x4C\xF9\xC7\x90\x2A\xC6\xEB\xC0\x4F\x81\x87\x80\x45\xE0\xAF\xB1\xED\xD4\x33\xB5\x00\xAF\x74\x1E\x70\x15\xDD\xAB\x56\x76\x02\xEF\xA3\x0B\xF8\x3B\xE8\x7E\x96\xF2\x4C\x65\x5B\x4E\xD2\xBD\x66\xE7\x15\xBA\x6B\x96\x5F\x00\x7E\x03\x1C\x01\x9E\x06\x8E\xC7\xB5\x26\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x4D\xD7\x7F\x00\x1F\x00\xD6\x0A\x18\x44\x1E\xFC\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82\x03\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x46\x6F\x6C\x64\x65\x72\x04\x08\x00\x00\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\xF0\x00\x00\x00\xF0\x08\x06\x00\x00\x00\x3E\x55\xE9\x92\x00\x00\x00\x06\x62\x4B\x47\x44\x00\xFF\x00\xFF\x00\xFF\xA0\xBD\xA7\x93\x00\x00\x07\xB9\x49\x44\x41\x54\x78\x9C\xED\xDD\xCD\x8F\x55\xE5\x1D\xC0\xF1\xAF\xA3\x02\x8A\x14\xBB\x61\x14\x44\xE3\x8A\x76\x2B\xDA\xA4\xD1\xA2\xC6\x5A\xD3\x74\x03\xA8\x11\x37\xAC\x5C\xB4\x10\x09\x4D\x77\x2E\xDA\x7F\xC0\x9A\x18\x43\xA2\x2B\x2B\xBE\x80\xB6\x31\x0A\x49\x6D\x8C\x66\x00\x35\xBA\x10\x4C\x5C\x58\xEC\xAA\x35\x26\x54\x88\x82\xA1\x94\x99\x61\xEA\x74\xF1\x48\x62\x70\x2E\x73\x2F\xF7\x79\x39\xBF\x7B\xBF\x9F\xE4\xB7\x7D\xCE\x39\x73\xCE\x77\xEE\xFB\xBD\x20\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24",
				"\x49\x92\x24\x49\x92\x62\xBB\xAC\xF5\x0E\x0C\x60\x39\x70\x07\xB0\x1E\x58\xF7\xED\x4C\x02\x2B\x81\x15\xC0\x15\xED\x76\xAD\x2F\x73\xC0\xBF\x80\x0F\x81\xD7\x80\x57\x81\xD9\xA6\x7B\x24\x15\x36\x09\xEC\x04\x0E\x01\x33\xC0\xFC\x08\xCD\x67\xC0\xFD\xF9\xFE\x54\x52\x77\xDC\x05\xEC\x07\xCE\xD1\x3E\xB4\xD2\xF3\x38\x30\x91\xE5\xAF\x26\x35\x76\x0F\xF0\x1E\xED\xA3\xAA\x3D\xCF\x61\xC4\x0A\x6C\x35\xB0\x87\xF6\x21\x19\xB1\x34\xA0\x2D\xC0\x29\xDA\x07\xD4\x85\x31\x62\x85\xB1\x0C\x78\x86\xF6\xD1\x74\x6D\x8C\x58\x9D\xB7\x12\x38\x40\xFB\x58\xBA\x3A\x46\xAC\xCE\x9A\x04\x8E\xD0\x3E\x92\xAE\x8F\x11\xAB\x73\x7E\x80\xF1\x0E\x32\x7B\xE8\xFE\x1B\x54\x34\x26\x96\x01\x07\x69\x1F\x45\xB4\xF1\x96\x58\x9D\xF0\x34\xED\x63\x88\x3A\x46\xAC\xA6\x1E\xA2\x7D\x04\xD1\xC7\x88\xD5\xC4\x6A\x7C\x9D\xD7\x88\x15\xD6\x5E\xDA\x5F\xF8\xA3\x34\x3E\xB1\xA5\x6A\xEE\xA1\xFD\x05\x3F\x8A\xE3\x2D\xB1\xAA\x78\x97\xF6\x17\xFB\xA8\x8E\x11\xAB\xA8\x3B\x69\x7F\x91\x8F\xFA\x18\xB1\x8A\xD9\x4F\xFB\x0B\x7C\x1C\xC6\x88\x95\xDD\x24\xE3\xF1\x61\xFC\xAE\x8C\x11\x2B\xAB\xDF\x52\xF6\x82\x9D\x06\x76\x03\x9B\x80\x9B\x80\x2B\xEB\x1C\x56\xDF\x26\x48\x51\x19\xB1\x42\x3A\x44\xB9\x0B\xF5\x25\xD2\x6B\xCB\x5D\x67\xC4\x0A\x69\x39\x65\xBE\x80\x6E\x0E\xF8\x75\xC5\xE3\xC8\xC1\x88\x15\xCE\x7D\x94\xB9\x30\x7F\x53\xF3\x20\x32\x32\x62\x85\xF2\x18\xF9\x2F\xC8\x97\xAA\x1E\x41\x7E\x46\xAC\x30\x72\x5F\xA8\x67\x89\xF1\x98\x77\x31\x46\xAC\x10\x3E\x20\xEF\x45\xB8\xBB\xEE\xEE\x17\x65\xC4\xEA\xBC\x7F\x92\xF7\x02\xDC\x54\x75\xEF\xCB\x33\x62\x75\xDA\x97\xE4\xBD\xF8\x6E\xAC\xBB\xFB\x55\x4C\x00\x7F\xA2\x6E\xC4\x7E\x8A\x49\x7D\xC9\xFD\x12\x52\xD7\xDE\xA4\x91\x8B\x11\x6B\x68\x25\x7E\x9D\x70\x3E\xF3\x7A\x91\x7E\x41\x71\x50\x13\xC0\xB3\xC0\xD6\xD6\x3B\x32\x86\x66\x81\x33\xC0\x49\xE0\x04\x70\x14\xF8\x14\x38\x4C\xFA\x79\x9F\x33\xED\x76\xAD\xAD\xDC\xB7\x1A\xA3\xAE\xC5\x63\x62\xE7\xE2\x33\x43\x7A\x37\xE1\x4E\xD2\xFB\xFA\xC7\x8A\x01\x0F\xCE\x88\xBB\x3B\xE7\x80\x7D\xC0\x86\x9E\x67\x6F\xC4\x18\xF0\xA5\x31\xE2\xEE\xCF\x3B\xC0\xDD\xBD\x4E\xE0\xA8\x30\xE0\x4B\xD7\xE2\x89\x2D\x67\xF0\xD9\x0F\xAC\x5D\xF8\x14\xC6\x67\xC0\xC3\xF1\x96\x38\xC6\x9C\x02\x1E\xEC\x71\x0E\x43\x33\xE0\xE1\x19\x71\x9C\xD9\x05\x2C\x5D\xF8\x34\xC6\x64\xC0\x79\x78\x77\x3A\xCE\x4C\x91\x7E\x71\x73\x24\x18\x70\x3E\xDE\x12\xC7\x99\x23\xC0\xAA\x85\x4F\x63\x2C\x06\x9C\x97\x11\xC7\x99\x23\xA4\x5F\xE0\x0C\xCD\x80\xF3\x33\xE2\x38\xF3\x36\xC1\x1F\x13\x1B\x70\x19\x3E\x26\x8E\x33\xBB\x16\x3E\x85\x31\x18\x70\x39\x46\x1C\x67\x1E\x5E\xF8\x14\x76\x9F\x01\x97\xE5\xDD\xE9\x18\x73\x12\xB8\xAE\xC7\x39\xEC\x34\x03\x2E\xCF\x5B\xE2\x18\xF3\x7C\x8F\xF3\xD7\x69\x06\x5C\x87\xB7\xC4\xDD\x9F\x6F\x48\xBF\x11\x16\x8A\x01\xD7\xE3\x2D\x71\xF7\xE7\x60\xAF\x93\xD7\x55\x06\x5C\xD7\x04\xF0\x24\xED\x2F\x54\xA7\xF7\xFC\xAC\xE7\xD9\xEB\x20\x03\x6E\xE3\x7E\xE0\x33\xDA\x5F\xAC\xCE\xF7\x67\xDF\x45\xCE\xDB\x50\xFC\x4A\x9D\xD1\xB2\x04\xD8\x0C\x6C\x04\x6E\x25\xFD\xF0\x9B\xDF\x81\xD5\xDE\x1C\xB0\x06\x38\xDE\x7A\x47\xFA\xE1\x2D\xB0\x22\xB8\x82\xF4\x0F\x6E\x33\xE9\xD9\xE2\x69\xCA\xDE\x0A\xEF\xA8\x73\x58\xC3\x33\x60\x45\xB4\x06\xD8\x4B\xB9\x80\xA7\xEA\x1D\xCA\x70\x0C\x58\x91\x6D\x23\xDD\xE5\xCD\x7D\x1D\x4F\x03\x57\x55\x3C\x8E\x4B\x66\xC0\x8A\x6E\x3B\x65\x6E\x85\xEF\xCD\xBD\xA3\xFE\xDC\x86\xF4\x7D\xBB\x80\x57\x0A\xAC\xBB\x3E\xF7\x82\x06\x2C\x2D\xEC\x77\xA4\xEF\x87\xCE\x69\x5D\xE6\xF5\x0C\x58\xEA\xE1\x73\xE0\x2F\x99\xD7\x34\x60\xA9\xA2\xD7\x32\xAF\x97\xFD\xD3\x49\x06\x2C\xF5\x76\x38\xF3\x7A\x2B\x32\xAF\xE7\x3B\xB1\xA4\x8B\x58\x42\xDE\xC7\xC1\x33\xC0\xB2\x8C\xEB\x19\xB0\xB4\x88\x4E\x5F\xCF\xDE\x85\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60",
				"\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x33\x60\x29\x30\x03\x96\x02\x2B\x11\xF0\x6C\xE6\xF5\x96\x64\x5E\x4F\xEA\x57\xEE\x6B\x6F\x26\xF3\x7A\x45\x02\xFE\x4F\xE6\xF5\xAE\xCF\xBC\x9E\xD4\xAF\xD5\x99\xD7\x3B\x9D\x79\xBD\x10\x01\xAF\xCF\xBC\x9E\xD4\xAF\xDB\x32\xAF\x17\x22\xE0\x63\x99\xD7\xDB\x94\x79\x3D\xA9\x5F\x1B\x33\xAF\xF7\xEF\xCC\xEB\x15\xF1\x1C\x30\x9F\x71\xA6\x81\x35\x55\x8F\x40\x82\xB5\xA4\x6B\x2F\xE7\xB5\xFC\x6C\xEE\x9D\x2C\x71\x0B\xFC\x69\xE6\xF5\x96\x02\x7F\xCC\xBC\xA6\xB4\x98\x27\x48\xD7\x5E\x4E\xB9\xDB\x28\xE2\x17\xE4\xFD\xAF\x75\x7E\xB6\xD5\x3C\x08\x8D\xB5\x1D\x94\xB9\x86\x7F\x5E\xF3\x20\x2E\xD5\xD5\xA4\xA7\xCB\x73\x1F\xFC\x1C\xB0\xBD\xE2\x71\x68\x3C\xED\x00\xFE\x47\xFE\xEB\x77\x1A\xB8\xAA\xE2\x71\x0C\xE5\x20\x65\xFE\x83\xCD\x03\x2F\x03\x37\xD4\x3B\x14\x8D\x89\xB5\xC0\x9F\x29\x77\xDD\x4E\xD5\x3B\x94\xE1\xED\xA4\xDC\x1F\xE2\xFC\x7F\xB3\xE7\x81\x07\x80\x9B\xF1\xCD\x1E\x1A\xDC\x12\xD2\xB5\xF3\x20\xF0\x22\xF9\x9F\xB0\xBA\x70\x1E\x2D\x71\x10\x97\x95\x58\x14\x58\x05\x7C\x0E\x5C\x59\x68\x7D\x29\x92\x39\xD2\xBD\xC6\x2F\x72\x2F\x5C\xEA\xBD\xD0\xC7\x81\xBF\x15\x5A\x5B\x8A\xE6\xAF\x14\x88\x17\xCA\x7E\x98\xC1\x97\x7E\xA4\xE4\xF1\x52\x0B\x97\x0C\xF8\x20\xF0\x6E\xC1\xF5\xA5\x08\x0E\x00\xEF\x94\x5A\xBC\xF4\xC7\x09\x7F\x5F\x78\x7D\xA9\xCB\xE6\x81\x3F\x94\xDC\x40\xE9\x80\xA7\x80\x3D\x85\xB7\x21\x75\xD5\x0B\xC0\xA1\x92\x1B\x28\xF5\x2C\xF4\x77\x5D\x0F\xFC\x1D\x58\x59\x61\x5B\x52\x57\x9C\x04\x7E\x4C\xA1\x27\xAF\xCE\xAB\xF1\x8D\x1C\xC7\x80\x47\x2A\x6C\x47\xEA\x92\x47\x28\x1C\x2F\xC0\xE5\xA5\x37\xF0\xAD\x4F\x80\x49\xF2\x7F\xBE\x52\xEA\xA2\xA7\x48\x1F\x86\x28\xAE\xC6\x5D\xE8\xF3\x96\x02\x6F\x00\x77\x57\xDC\xA6\x54\xDB\x5B\xC0\xAF\xC8\xFF\xD5\x52\x0B\xAA\x19\x30\xC0\x0A\xD2\xD3\xEA\xB7\x54\xDE\xAE\x54\xC3\xC7\xC0\x06\xE0\xEB\x5A\x1B\xAC\xFD\xAD\x94\xA7\x81\x5F\x02\x1F\x55\xDE\xAE\x54\xDA\x11\xE0\x5E\x2A\xC6\x0B\x6D\xBE\x56\xF6\x38\xE9\xBF\xD4\x9B\x0D\xB6\x2D\x95\x30\x45\x7A\x68\x78\xBC\xF6\x86\x6B\x3D\x89\x75\xA1\x59\xD2\x47\xB7\x7E\x08\xFC\xA4\xD1\x3E\x48\x39\x3C\x05\x6C\x05\xFE\xDB\x7A\x47\x5A\x79\x80\xF4\x9A\x59\xC9\x8F\x72\x39\x4E\xEE\xF9\x0A\xD8\x8C\x00\xB8\x0E\xD8\x0D\x7C\x43\xFB\x13\xE3\x38\x8B\xCD\x2B\xA4\x97\x45\x75\x81\x3B\x29\xFB\x6D\x1E\x8E\x33\xCC\x1C\x20\x3D\x7F\xA3\x45\x6C\x00\xF6\x91\x1E\x2B\xB7\x3E\x69\xCE\x78\xCF\x2C\xF0\x3A\x70\x07\x1D\x54\xFB\x75\xE0\x41\xAD\x02\xB6\x90\xBE\xDC\xFD\xA7\xE4\xFF\x9A\x4F\x69\x21\x33\xC0\xFB\xC0\xAB\xC0\x5E\xE0\x44\xDB\xDD\xE9\xAD\xEB\x01\x7F\xD7\xD5\xC0\xED\xA4\x9F\x5A\x59\x07\xFC\x88\x14\xF8\xB5\xC0\x35\xF8\xBD\x58\x1A\xCC\x2C\xE9\x67\x80\x4E\x91\xDE\xB3\x7C\x14\xF8\x07\xF0\x21\xF0\x1E\x70\xB6\xDD\xAE\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\x24\x49\x92\xFA\xF5\x7F\xE6\x8F\xE9\xD0\xA2\xF0\x73\xB6\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82\x03\x00\x00\x00\x00\x00\x00\x00\x0B\x00\x00\x00\x00\x00\x00\x00\x0B\x00\x00\x00\x49\x6E\x66\x6F\x72\x6D\x61\x74\x69\x6F\x6E\xF6\x13\x00\x00\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\xF0\x00\x00\x00\xF0\x08\x06\x00\x00\x00\x3E\x55\xE9\x92\x00\x00\x00\x06\x62\x4B\x47\x44\x00\xFF\x00\xFF\x00\xFF\xA0\xBD\xA7\x93\x00\x00\x13\xAB\x49\x44\x41\x54\x78\x9C\xED\xDD\x79\xB4\x9D\x55\x79\xC7\xF1\xEF\x1D\x32\x49\xD2\x24\x24\x24\x08\x22\x09\x01\xB4\xC8\x20\x22\x50\x21\x8A\xD0\xAC\x85\xB4\xA2\x4C\x22\xB5\xAD\x22\x93\x50\xAA\x32\x88\x74\xD9\x2A\x94\x41\x71\x68\x0B\x69\x5D\x42\x5B\x5D\x62\x1D\x12\x2B\xB5\x16\x91\x94\x55\x28\x15\x88\x80\x46\x08\x24\x4C\x09\x19\x08\x4B\xC4\xCC\x90\x81\xE4\x92\x9C\xFE\xF1\x9C\x6B\x2E\xF1\xE6\xDE\x73\xEF\x7D\x9E\xBD\xDF\xE1\xF7\x59\xEB\x59",
				"\x61\x69\xD8\xBC\x7B\xBF\xCF\x3E\xE7\x3D\xFB\xDD\x03\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\xE4\xD5\x96\xFB\x02\xA4\x65\x13\x80\x29\xCD\xD8\x17\x78\x7D\xF3\x7F\x9B\x00\x4C\x6C\xFE\x39\x02\x18\xDB\xFC\xFB\xC3\x81\xDD\x9A\xFF\xBC\x11\xD8\xDA\xFC\xE7\x75\xC0\x16\x60\xF5\x4E\xF1\x02\xB0\xAC\x47\xAC\x89\xAA\x88\xF8\x51\x07\x2E\x9E\x49\xC0\xA1\xCD\x38\xA4\xF9\xE7\x01\xC0\x98\xC4\xD7\xF1\x12\xB0\x08\x78\xBC\x19\x8F\x35\xE3\x37\x89\xAF\x43\xFA\xA0\x0E\x9C\x57\x07\xF0\x66\xE0\x58\x60\x7A\x33\xA6\x66\xBD\xA2\xFE\xBD\x00\xCC\x03\xEE\x07\x1E\x00\x1E\x66\xC7\xB7\xBB\x24\xA6\x0E\x9C\xDE\x81\xC0\x49\xC0\x7B\x80\x77\xB2\xE3\x31\xB7\xAC\x36\x00\x3F\x05\xEE\x04\xE6\x00\x8B\xF3\x5E\x8E\x88\xAF\x0E\xE0\x78\xE0\x9F\xB0\xE4\x6E\x54\x3C\x16\x01\x33\x81\xE3\x80\x76\x87\xF6\x13\x49\xAE\x1D\x7B\x1C\xBE\x09\xF8\x15\xF9\x3B\x55\xAE\x58\x09\x7C\x0B\x98\x81\x3A\xB3\x94\xC0\x1B\x81\xAB\x81\xE7\xC8\xDF\x79\x8A\x16\xCB\x81\xAB\x80\x37\x0C\xB6\x71\x45\x22\x74\x02\xA7\x02\x77\x00\xDB\xC8\xDF\x51\x8A\x1E\xAF\x02\x3F\x06\x4E\xC1\x7E\x5E\x88\x64\x31\x1A\xB8\x00\x78\x9A\xFC\x9D\xA2\xAC\xB1\x14\xB8\x12\x18\x37\xC0\xB6\x17\x19\xB4\xBD\x81\x2F\x02\x6B\xC9\xDF\x01\xAA\x12\x6B\x81\x1B\xB0\xC9\x29\x22\x21\xF6\xC0\x92\x6C\x13\xF9\x13\xBE\xAA\xB1\x05\xB8\x05\x75\x64\x71\x34\x01\x1B\x98\x7A\x89\xFC\x09\x5E\x97\xD8\x88\x8D\xE0\x4F\xEE\xFF\xF6\x88\xF4\x6E\x04\xF0\x69\x60\x3D\xF9\x13\xBA\xAE\xB1\x0E\xF8\x14\x36\xAF\x5B\xA4\x65\x27\x53\x8F\x49\x17\x65\x89\x45\xC0\x07\xFA\xBC\x63\x22\xC0\x9B\x80\xBB\xC9\x9F\xB0\x8A\xDE\xE3\xBF\xB1\x85\x1D\x22\xAF\xD1\x89\xBD\xCE\xD8\x4C\xFE\x24\x55\xF4\x1D\x9B\xB1\x31\x09\x3D\x56\x0B\x00\x6F\x05\x7E\x41\xFE\xC4\x54\x0C\x2C\xE6\x03\x47\xF5\x72\x3F\xA5\x26\x86\x01\xD7\x61\x33\x83\x72\x27\xA3\x62\x70\xD1\x05\xFC\x2D\xF6\x04\x25\x35\x32\x15\x5B\xCF\x9A\x3B\x01\x15\x3E\xF1\x10\xFA\x6D\x5C\x1B\xE7\x02\x2F\x93\x3F\xE9\x14\xBE\xF1\x12\x70\x36\x35\x53\xA7\x05\xFD\xA3\x80\xAF\x01\x1F\xC9\x7D\x21\x43\xB0\x19\x78\x16\xDB\xB3\x6A\x69\xF3\xCF\x17\xD9\xB1\xAF\xD5\x2A\xEC\xDD\x29\xD8\x2E\x19\x1B\x9B\xFF\xBC\x1B\x3B\x06\x7D\xC6\xB1\x63\x0F\xAD\x09\xD8\x64\x89\xA9\xD8\x5E\x5B\x53\x81\xFD\xB0\xB6\x2A\xAB\x6F\x00\x17\x03\xAF\xE4\xBE\x90\x14\xEA\xD2\x81\xA7\x02\xB7\x01\x87\xE7\xBE\x90\x01\x58\x03\xCC\x05\x7E\x89\xED\x49\x35\x1F\xEB\xBC\xDB\x83\xFF\xBB\x1D\xC0\x34\xE0\x30\x6C\x4F\xAE\xB7\x01\xC7\x00\xE3\x83\xFF\xBB\x9E\xE6\x01\xA7\x63\x4B\x18\xA5\xE4\x4E\xC4\xBE\x99\x72\x3F\xE2\xF5\x17\x2B\x81\xEF\x02\xE7\x01\x07\x51\xAC\x0F\xD7\x36\xEC\x9A\xCE\x07\xBE\x47\x79\xDA\x73\x46\x44\x63\x48\x3A\x17\x51\xEC\x51\xE6\xC7\xB0\x51\xD4\xA3\x29\xD7\xDA\xD8\x0E\xE0\x0F\x80\x6B\xB0\xA7\x83\xDC\xED\xB8\xAB\xE8\xC2\x96\x7C\x4A\xC9\xB4\x03\x5F\x26\x7F\x02\xF5\x16\x4F\x00\x9F\xC3\x76\xA3\xAC\x8A\x83\xB0\xC9\x15\x4F\x92\xBF\x7D\x7B\x8B\x1B\x28\xD6\x13\x8D\xF4\x61\x14\xF0\x03\xF2\x27\x4D\xCF\xD8\x08\x7C\x13\xFB\x2D\x59\x75\xD3\x81\x5B\x29\xDE\xB2\xCB\xD9\xC0\xC8\xC0\x7A\x8B\x83\x31\xC0\xFF\x91\x3F\x59\xBA\x63\x29\x70\x09\x3B\x4E\x4B\xA8\x93\x71\xC0\x65\xD8\x48\x79\xEE\xFB\xD0\x1D\xF7\x60\x3B\xA9\x48\x01\x8D\x07\x1E\x24\x7F\x92\x34\xB0\xCD\xCE\xCF\xA4\x5C\xBF\x6B\xA3\x74\x02\x67\x51\x9C\xE9\xAA\x73\xD1\x16\x3E\x85\x33\x09\x78\x84\xFC\xC9\xF1\x18\xB6\xEC\x4D\xBF\xB7\x7A\x37\x03\xF8\x39\xF9\xEF\xD3\x2F\xB1\x1D\x56\xA4\x00\xF6\x00\x16\x92\x37\x21\x16\x62\xBB\x2C\xAA\xE3\xF6\xAF\x0D\x38\x8D\xFC\x03\x5E\x8F\x63\x13\x5A\x24\xA3\xB1\xE4\x7D\x34\x5B\x83\x2D\x43\xD4\xD2\xB6\x81\xEB\xC4\x5E\xF1\xAC\x24\xDF\xFD\x7B\x14\xD8\x3D\xBA\xA2\xD2\xBB\x31\xE4\xFB\xCD\xBB\x0D\x3B\x2A\x45\x37\x7F\xE8\x26\x02\x37\x63\x33\xCC\x72\xDC\xCB\xB9\x68\x60\x2B\xB9\x51\xC0\xBD\xE4\xB9\xE1\x0B\xA9\xC7\xEB\xA0\xD4\xA6\x93\xEF\xB1\xFA\x6E\xF4\x8A\x29\x99\x76\xF2\xBC\xE7\xED\x5E\x7B\x3A\x22\xBE\x8A\xB5\x35\x02\x5B\xA3\xDD\x45\xFA\xFB\x3B\x0B\x8D\x61\x24\xF1\x15\xD2\xDF\xDC\xA5\xD8\x19\xBE\x92\xC6\x51\xD8\x46\x76\xA9\xEF\xF3\xE7\x53\x54\xAE\xCE\x2E\x22\xFD\x4D\xFD\x57\xF4\x1B\x29\x87\x31\xD8\xEC\xB5\xD4\xF7\xFB\xFC\x04\x75\xAB\xA5\x13\x49\xBB\x30\x61\x13\xF0\xE1\x24\x35\x93\xBE\x9C\x43\xDA\xCD\x06\xBB\x80\x3F\x4C",
				"\x52\xB3\x1A\xD9\x97\xB4\xAF\x1B\x9E\x03\x8E\x4C\x52\x33\x69\xC5\xE1\xC0\x12\xD2\xDD\xFF\xD5\xD8\x1A\x72\x71\x30\x0A\x9B\x39\x93\xEA\xE6\xDD\x8B\x5E\x0F\x15\xD1\x44\xE0\x3E\xD2\xE5\xC1\xC3\x68\x64\xDA\xC5\x37\x48\x77\xD3\xB4\x62\xA5\xD8\x46\x00\xDF\x26\x5D\x3E\x7C\x2B\x4D\xB5\xAA\xEB\x5C\xD2\xDD\xAC\x6B\xD0\x6B\x84\x32\x68\xC3\x46\x8B\x53\xE5\x85\xC6\x41\x06\x69\x1A\x69\x4E\x04\xDC\x8E\x2D\x7B\x93\x72\xB9\x98\x34\xB3\xB7\x5E\x46\x5B\xD6\x0E\x58\x27\xF0\x33\xD2\x74\xDE\x8F\x27\xAA\x93\xF8\xBB\x00\x9B\xD6\x1A\x9D\x27\x0F\x63\x07\x01\x48\x8B\xAE\x25\xFE\xA6\x6C\xA3\xDC\x5B\xCC\x8A\x39\x9B\x34\x9D\xF8\xEA\x34\xD5\x29\xBF\x23\x89\x7F\xDF\xBB\x1D\xF8\x58\xAA\x0A\x49\xB8\x8B\x88\x7F\x9C\xEE\x02\x8E\x48\x55\xA1\xB2\xEA\x24\xCD\x2B\xA3\x2B\x52\x55\x48\x92\xB9\x84\xF8\xBC\x99\x8F\x1E\xA5\xFB\xF4\xD7\xC4\xDF\x84\x6B\x92\xD5\x46\x52\xBB\x81\xF8\xFC\xB9\x32\x59\x6D\x4A\xE6\x40\xE2\xA7\xCC\x7D\x0F\xBD\x2A\xAA\xB2\x36\xE0\xDF\x88\xCD\xA1\x4D\xC0\xFE\xA9\x2A\x54\x26\x77\x13\xDB\xF0\xF7\xA2\x9D\x33\xEA\x60\x24\xF1\x33\xB6\xE6\x24\xAB\x4D\x49\x9C\x4A\x6C\x83\x2F\x41\xD3\x23\xEB\x64\x22\x76\x2E\x52\x64\x4E\xBD\x37\x59\x6D\x0A\x6E\x38\xF0\x0C\x71\x0D\xBD\x99\xFA\x8C\x1E\x0E\xC7\xB6\x70\x9D\x05\x2C\xC6\x46\x4E\xBB\x9A\xFF\x3C\xAB\xF9\xFF\xD5\xE5\x29\xE4\xAD\xC4\x6E\x2E\xBF\x18\x6D\xEE\x00\xC0\x5F\x11\xFB\x49\xF9\xD1\x74\x55\xC9\xEA\x74\x6C\x15\x55\x7F\xED\xF1\x5C\xF3\xEF\xD6\xC1\x9F\x13\x9B\x5B\xB5\x9F\xC1\x37\x11\x58\x4F\x5C\x03\x7F\x3D\x5D\x55\xB2\x69\x07\x6E\x62\xE0\x6D\x73\x53\xF3\xDF\xAD\xBA\x5B\x89\xCB\xAF\xB5\xD4\xFC\xA7\x59\xE4\x01\x64\x8B\xB1\x5D\x1D\xAA\x6E\x30\x9D\xB7\x67\x27\xAE\xBA\xD1\xC4\xFE\x44\xBB\x3E\x5D\x55\x8A\x65\x4F\xEC\xD0\xAF\x88\x46\xED\xC2\x8E\xBF\xAC\xBA\xD3\x19\x7A\x5B\xD5\xE1\x71\xFA\x48\x60\x2B\x31\xB9\xB6\x01\x3B\x19\xA4\x76\x6E\x24\xEE\x53\xF1\xEA\x74\xD5\xC8\x66\x38\x3E\xBB\x54\x2C\xA3\x1E\x83\x31\xD7\x11\x97\x6F\x5F\x49\x58\x8F\x42\xD8\x9B\xB8\x49\x1B\x0B\xA9\xC7\x48\xEB\x59\xF8\xB5\xD9\x07\x13\x5F\x7B\x0E\x23\x89\xDB\x77\x7A\x13\xF6\x44\x59\x1B\x5F\x22\xA6\x21\xB7\x51\x9F\xED\x5F\x67\xE3\xD7\x6E\xB3\x13\x5F\x7B\x2E\xEF\x20\x6E\xE5\x52\x6D\x7E\x0B\x8F\xC1\x46\xEF\x22\x1A\xF1\xAB\x09\xEB\x91\x9B\xE7\x26\x6F\x4B\x12\x5F\x7B\x4E\xB7\x10\x93\x7B\xAB\xA9\xC9\xF6\xC3\x97\x12\xD3\x80\x6B\x80\x09\x09\xEB\x91\x9B\xE7\x4F\x90\xCD\x89\xAF\x3D\xA7\xDD\xB1\xCE\x16\x91\x83\x9F\x48\x58\x8F\x2C\x3A\x80\x67\x89\x69\xBC\x8B\x13\xD6\xA3\x08\xBC\xDB\xAF\x4E\xA2\xBE\x44\x96\x62\x4B\x62\x2B\x2B\x6A\xCE\xF3\x42\x2A\xDE\x70\xBD\x50\x07\x1E\xBC\x61\xC4\x0D\x68\xBD\x3F\x61\x3D\x92\xFB\x09\x31\x8D\x76\x4A\xCA\x4A\x14\x84\x3A\xF0\xD0\x9C\x41\x4C\x2E\xDE\x9E\xB2\x12\x29\xED\x43\xCC\x56\x39\xBF\xA0\x9E\x6B\x7C\xD5\x81\x87\xA6\x0D\x78\x04\xFF\x76\x7C\x15\xCB\xF5\x24\x52\xCE\x85\x3D\x0F\xFB\x0D\xEC\xED\xB3\xD4\x33\x01\x65\x68\x1A\xC0\x55\x01\xE5\x76\x50\xC1\xCD\x12\xDB\x69\x6D\xA5\xCC\x40\xE3\xE1\x94\x95\x28\x18\x7D\x03\x0F\x5D\x1B\x30\x0F\xFF\xB6\x5C\x4A\xC5\x9E\x0A\x8F\xC3\xBF\x91\x1A\xC0\x99\x29\x2B\x51\x30\xEA\xC0\x3E\x3E\x44\x4C\x6E\x1E\x93\xB2\x12\xD1\xBE\x4A\xCC\xA7\x5C\xDD\x46\x9E\x7B\x52\x07\xF6\xD1\x89\xCD\x07\xF7\x6E\xCF\x1B\x13\xD6\x21\x54\x07\xF0\x02\xFE\x0D\x74\x49\xCA\x4A\x14\x90\x3A\xB0\x9F\xCB\xF0\x6F\xCF\xE7\xA9\xC8\x7A\xEB\x13\xF0\x6F\x9C\x4D\xC0\xF8\x94\x95\x28\x20\x75\x60\x3F\xE3\x88\x59\xDA\xFA\xAE\xE8\x0B\x4F\xF1\x09\x71\x6A\x40\x99\xB3\xB1\xF9\xD4\x22\x1E\xD6\x01\xFF\x11\x50\xEE\x69\x01\x65\x26\xB7\x18\xFF\x4F\xB6\x4A\x0D\x10\x0C\x92\xBE\x81\x7D\x1D\x87\x7F\x9B\x3E\x9D\xB4\x06\x01\x0E\xC4\xBF\x51\x9E\x48\x5A\x83\xE2\x52\x07\xF6\xD5\x06\x2C\xC2\xBF\x5D\xA7\x45\x5E\x74\xF4\x23\xF4\x49\x01\x65\xCE\x0A\x28\x53\xA4\x41\x4C\x6E\x9D\x18\x50\x66\x32\x73\xF0\xFF\x44\xFB\xFD\xA4\x35\x28\x2E\x7D\x03\xFB\x3B\x18\xFF\x76\x2D\xED\xDC\xE8\x61\xF8\x8F\xEC\xCD\x4F\x5A\x83\x62\x53\x07\x8E\xB1\x10\xDF\x76\x7D\x99\xC0\xF9\x0A\x91\x8F\xD0\x87\x01\xAF\x73\x2E\xF3\x87\xCE\xE5\x89\xEC\xCC\x7B\x34\x7A\x34\x70\x88\x73\x99\xBF\x15\xD9\x81\xA7\x07\x94\x79\x67\x40\x99\x22\x3D\x45\x1C\x5C\x16\xB6\x4F\x5B\x64\x07\xF6\x7E\xD5\xB3\x0A\x5B\x3A\x28\x12\xE9\x41\x6C\x7B\x26\x4F\xEA\xC0\xC0\x5D\xD8\x8E\x82\x22\x91\xB6\x01\xFF\xE3\x5C\x66\xE9\x3A\xF0\x9E",
				"\xD8\xDE\xCF\x9E\xEE\x71\x2E\x4F\x64\x57\xFE\xD7\xB9\xBC\x7D\x80\x3D\x9C\xCB\x04\xE2\x3A\xF0\xA1\x01\x65\xCE\x0D\x28\x53\xA4\x37\x0F\x04\x94\x19\x32\x90\x15\xD5\x81\xBD\x2F\x76\x2D\x15\x98\x96\x26\xA5\xB1\x00\xFF\xDF\xC1\xB5\xEE\xC0\x73\x81\xED\xCE\x65\x8A\xEC\x4A\x03\x78\xC8\xB9\xCC\x5A\x77\xE0\x79\xCE\xE5\x89\xF4\xC7\x3B\xE7\x4A\xD5\x81\x0F\x70\x2E\xEF\x31\xE7\xF2\x44\xFA\xB3\xC0\xB9\x3C\xEF\x3E\x01\xC4\x74\xE0\x09\xF8\x1F\xAC\xAD\x0E\x2C\xA9\x79\xE7\xDC\x78\x6C\xE3\x00\x57\x11\x1D\x78\x8A\x73\x79\x9B\xA8\xD7\xE1\x5B\x52\x0C\x8B\x80\x57\x9C\xCB\x9C\xE2\x5C\x5E\x48\x07\x9E\xEA\x5C\xDE\x12\x34\x81\x43\xD2\x7B\x15\x58\xEE\x5C\xE6\x14\xE7\xF2\x42\x3A\xF0\xBE\xCE\xE5\x2D\x73\x2E\x4F\xA4\x55\xDE\x4F\x7E\xDE\x5F\x6E\x21\x1D\x78\xB2\x73\x79\x4B\x9D\xCB\x13\x69\xD5\x32\xE7\xF2\xF6\x74\x2E\x2F\xA4\x03\x4F\x74\x2E\x6F\x99\x73\x79\x22\xAD\xF2\xFE\xF2\x70\x3F\xBF\x3A\x6A\x14\xDA\xD3\x8B\xCE\xE5\x89\xB4\xEA\xD7\xCE\xE5\xD5\xB2\x03\xAF\x76\x2E\x4F\xA4\x55\xDE\xB9\xE7\xFD\x74\x5A\x8A\x47\xE8\x55\xCE\xE5\x89\xB4\xCA\xBB\x03\x97\xE2\x1B\x78\x37\xE7\xF2\xF4\x0D\x2C\xB9\x78\x7F\x79\x78\xF7\x8D\x90\x0E\x3C\xC2\xB9\xBC\x0D\xCE\xE5\x89\xB4\x6A\xA3\x73\x79\xDE\x7D\x23\xA4\x03\x0F\x73\x2E\xAF\xCB\xB9\x3C\x91\x56\x6D\x71\x2E\xAF\x14\x1D\xD8\xFB\x22\xBD\x1B\x51\xA4\x55\xDE\xB9\x37\xDC\xB9\xBC\x90\x0E\xEC\x7D\x91\x5B\x9D\xCB\x13\x69\x55\x2D\xBF\x81\x25\x8D\xCD\x8E\x65\x6D\x72\x2C\x4B\x12\x8A\xE8\xC0\xDE\xDF\x98\xEE\x8F\x1D\x15\xE1\x39\xC9\x40\x93\x65\x7A\x57\xF8\x9F\x83\x11\x1D\xB8\xF0\x8F\x1D\x15\xF1\xF3\x82\x96\x55\x25\xDE\xB9\xE7\xFE\x73\x30\xA2\x03\x7B\x8F\x1A\x7B\x8F\x6A\x57\x85\xE7\x31\x33\x11\x87\x5B\x57\x41\xE1\xBF\x81\x23\xAC\xC0\xF7\x70\x28\xF7\x25\x58\x15\x31\x1C\x5B\xEE\x36\xD4\xF6\x5D\x86\x9E\x72\x76\x65\x1A\xBE\xB9\xEC\xBD\xBE\x38\xE4\x1B\xD8\xFB\xE5\xB7\xFB\xFC\xD1\x8A\xD8\x0A\x5C\xE1\x50\xCE\xE5\x94\xE4\x9B\x21\x03\xEF\xDC\xF3\xEE\x1B\x21\x1D\xD8\x7B\xFA\x99\xFB\xFC\xD1\x0A\xB9\x0D\x98\x39\x84\x7F\x7F\x66\xB3\x0C\xE9\x9D\x77\xEE\xB9\xCF\xEB\x8F\xE8\xC0\x85\x9F\x00\x5E\x31\x97\x32\xB8\x4E\x3C\xB3\xF9\xEF\xCA\xAE\x15\x7E\x65\x5D\x19\x3A\xB0\xFB\x2E\x06\x15\xB3\x1D\xF8\x24\x70\x06\x36\xFE\xD0\x9F\x15\xCD\xBF\xFB\x49\xB4\x59\x7E\x7F\xBC\x73\xCF\xBD\x03\x47\x9C\x1C\xEE\xFD\x98\x30\xC5\xB9\xBC\xAA\xBA\x0D\xB8\x1D\x38\x0D\x38\x05\x78\x3B\x3B\xF6\x27\x5B\x8E\x1D\xCD\xFA\x9F\xD8\x88\xB3\x66\xB7\xB5\xC6\x7B\x00\xD5\xFD\x11\x3A\xA2\x03\x7B\x4F\x0A\x98\xE2\x5C\x5E\x95\x6D\x05\x66\x35\x43\x86\x6E\x8A\x73\x79\xDE\x3B\x7C\x84\x3C\x42\x2F\x73\x2E\x6F\x8A\x73\x79\x22\xAD\xDA\xCF\xB9\x3C\xF7\x0D\x1A\x23\x3A\xB0\xF7\x45\x4E\x03\x3A\x9C\xCB\x14\xE9\x4F\x27\xFE\x5F\x1E\xCB\x9C\xCB\x0B\xB1\x3B\xBE\x2F\xBF\x1B\xC0\x9B\x92\xD6\x40\x04\xDE\x82\x7F\x1E\x8F\xF5\xBE\xC8\x88\x6F\xE0\x35\xC0\x7A\xE7\x32\x43\x4E\x76\x13\xE9\x83\x77\xCE\x45\xF4\x8B\xB0\xE5\x84\x8B\x9D\xCB\x3B\xD4\xB9\x3C\x91\xFE\x1C\xEC\x5C\x9E\x77\x9F\x00\xE2\x3A\xF0\xE3\xCE\xE5\xBD\xCD\xB9\x3C\x91\xFE\x78\xE7\x5C\xC8\x09\x9B\x51\x1D\xD8\xFB\x62\x8F\x41\x9B\x0F\x48\x3A\xED\x58\xCE\x79\x2A\x55\x07\xF6\xFE\x06\x1E\x0F\xBC\xD9\xB9\x4C\x91\x5D\x39\x18\xFF\x01\x27\xEF\x3E\x01\xC4\x75\xE0\xF9\x01\x65\x1E\x1B\x50\xA6\x48\x6F\xA6\x07\x94\xB9\x20\xA0\xCC\xB0\x0E\xBC\x12\x78\xDE\xB9\xCC\x13\x9C\xCB\x13\xD9\x95\xE3\x9D\xCB\x5B\x4E\x09\x4F\x18\x99\x85\xEF\x3B\xB4\xD5\x68\x42\x87\xC4\xEB\x04\xD6\xE2\x9B\xBB\xDF\x89\xBA\xD8\xC8\x81\xA1\xB9\xCE\xE5\xED\x0E\x1C\xE9\x5C\xA6\xC8\xCE\xDE\x01\x8C\x73\x2E\xF3\x01\xE7\xF2\x7E\x2B\xB2\x03\x47\x5C\xF4\x1F\x05\x94\x29\xD2\xD3\x7B\x02\xCA\xF4\xFE\x32\x4B\xA2\x13\x78\x19\xDF\x47\x91\x90\x91\x3C\x91\x1E\x9E\xC0\x37\x67\xD7\x53\xE2\x9F\x7E\x3F\xC1\x7F\x3E\xE9\x41\x49\x6B\x20\x75\x72\x18\xFE\xF9\xFA\xA3\xC8\x0B\x8E\x9E\x1C\x31\x27\xA0\xCC\x33\x03\xCA\x14\x81\x98\xDC\x8A\xE8\x03\xC9\x1C\x80\xFF\x27\xDA\x93\x49\x6B\x20\x75\xD1\x86\xCD\x57\xF6\xCE\xD7\xD2\x6F\x8B\xBC\x08\xFF\x46\xD1\xA4\x0E\xF1\x76\x3C\x25\xFC\xB2\x49\x31\xBF\xF8\xCE\x80\x32\x2F\x08\x28\x53\xEA\xED\xDC\x80\x32\x4B\xFD\xF8\xDC\xED\x38\xFC\x3F\xD9\x36\x61\xF3\xA3\xE5\xB5\x86\x03\x67\x61\x93\x68\x16\x63\xC7\xDC\x6C\xC3\x76\x82\xF8\x21\x70\x0E\xF0\xBA\x5C\x17\x57\x60\xE3\xB0\x9C\xD2\x93\x62\x2F\xDA\x81\x5F\xE1\xDF",
				"\x38\xDA\xD3\xF8\xB5\x4E\x07\x9E\xA3\xFF\x76\x5B\x89\x7D\xDB\xB4\xE5\xB9\xCC\x42\xBA\x1C\xFF\xFC\x5C\x41\x85\x56\xD0\xCD\x24\xA6\x81\x74\xF0\x99\x25\xC9\x4D\x0C\xBC\xFD\xBE\x8B\x8E\x6E\x05\xCB\xA1\xE5\xF8\xE7\xE7\xDF\xA5\xAC\x44\xB4\xE9\xF8\x37\x50\x03\x7B\x5C\xAC\xBB\xC1\x74\xDE\xEE\xF8\x3E\xFA\x26\xFE\x33\x62\x72\xF3\xA8\x94\x95\x88\xD6\x4E\xCC\xA7\x5C\xDD\xCF\xB5\x3D\x9D\xA1\xB7\xE1\xC7\x93\x5F\x75\x71\xB4\x01\x8F\xE0\x9F\x97\xCF\x52\xC1\x0F\xC6\xAB\x88\xF9\xA4\xFB\xE3\x94\x95\x28\x10\xAF\xE3\x45\xD7\x61\x0B\x45\xEA\xE8\x14\x62\x72\xF2\x33\x29\x2B\x91\xCA\x1B\x80\x57\xF1\x6F\xAC\x79\x54\xF0\xD3\xAE\x05\x67\xE1\xD7\x86\x75\x1C\x10\x6C\x03\x1E\xC5\x3F\x1F\xBB\x80\xBD\x12\xD6\x23\xA9\x3B\x88\xF9\xC4\x3B\x2D\x65\x25\x0A\x62\x36\x7E\xED\x77\x5F\xE2\x6B\x2F\x82\x0F\x12\x93\x8B\xA1\x73\x9F\x73\x7B\x3F\x31\x8D\xF6\x24\xF5\x1B\x91\xF6\x78\x7C\xEE\x8E\x4D\x54\xE8\x95\x47\x0B\x86\x03\xCF\x10\x93\x8B\x27\x27\xAC\x47\x72\x1D\xC4\xCC\x37\x6D\x60\xC7\x65\xD6\xC9\x66\x7C\xDB\xAF\x4E\x13\x63\xAE\x20\x26\x07\x97\x50\xE2\xA5\x83\xAD\xFA\x04\x31\x8D\xB7\x06\x98\x98\xB0\x1E\xB9\x79\xCF\x1C\xF2\xDE\x85\xA2\xA8\x26\x61\x03\x77\x11\x39\x78\x71\xC2\x7A\x64\x33\x1A\xEB\x6C\x11\x0D\x78\x73\xC2\x7A\xE4\xA6\x47\xE8\xC1\xF9\x3A\x31\xB9\xB7\x0A\xD8\x2D\x61\x3D\xB2\xFA\x02\x31\x8D\xB8\x8D\x98\x2D\x41\x8B\x48\x83\x58\x03\x77\x1C\xB0\x9D\x98\xDC\xBB\x26\x61\x3D\xB2\xDB\x0B\xFF\xDF\x70\xDD\xF1\x24\x30\x22\x5D\x55\xB2\xD1\x6B\xA4\x81\x19\x45\xDC\xC0\xD5\x46\x60\x72\xBA\xAA\x14\xC3\xDF\x13\xD3\x98\x0D\xE0\xDA\x84\xF5\xC8\x45\x13\x39\x06\x26\xEA\xA9\xAF\x01\x7C\x29\x61\x3D\x0A\x63\x0F\xFC\x37\xBD\xEB\x8E\x2E\x6C\x7B\xD0\xAA\xD3\x54\xCA\xD6\x1C\x4B\xCC\x24\xA2\x06\x96\xC3\x93\xD2\x55\xA5\x58\xBE\x48\xDC\xA7\xE2\xB3\xC0\xEF\xA5\xAB\x4A\x36\x5A\xCC\xD0\xB7\xB1\xC0\x52\xE2\xF2\xEC\xBA\x74\x55\x29\x9E\x09\xC4\x0D\xE9\x37\x80\x6F\x26\xAB\x49\x3E\x5A\x4E\xD8\xB7\xEF\x10\x97\x5F\x6B\xA9\xD7\xFB\xF3\x5E\x7D\x8A\xB8\x06\x6E\x10\xB3\x55\x4A\x11\x69\x41\xFF\xEF\xBA\x90\xD8\xDC\xAA\xDB\xE4\xA1\x5E\x0D\x07\x9E\x26\xAE\x91\x37\x53\x9F\x23\x59\xB4\xA5\xCE\x0E\x47\x03\xAF\x10\x97\x57\x75\x9C\xBE\xBB\x4B\xEF\x23\xF6\x93\x72\x19\xF5\x9A\xA5\x55\x77\x93\xB0\x1D\x5B\x22\x73\xEA\xA4\x64\xB5\x29\x89\xBB\x88\x6D\xF0\x9F\x52\x8F\xF7\xC3\x75\x37\x0A\x3B\x8B\x28\x32\x97\x7E\x9C\xAC\x36\x25\x72\x00\x31\x3B\x03\xF6\x8C\xD9\xD4\xE3\xB7\x5F\x5D\xB5\x11\x3B\x68\xD5\xC0\x26\x6D\x4C\x4B\x55\xA1\xB2\xB9\x92\xD8\xC6\x6F\x00\xD7\x27\xAB\x8D\xA4\xF6\x65\xE2\xF3\xE7\xF2\x64\xB5\x29\xA1\x4E\x6C\x87\x8D\xE8\x9B\xF0\xE9\x54\x15\x92\x64\x2E\x25\x3E\x6F\x1E\x45\x03\x57\xFD\x3A\x02\x1B\x3D\x8D\xBC\x11\xDB\xB1\x57\x0C\x52\x0D\x7F\x49\x7C\xE7\xED\x02\x0E\x4F\x55\xA1\xB2\xBB\x9A\xF8\x1B\xB2\x0D\x38\x3B\x4D\x75\x24\xD0\xB9\xC4\xAD\x30\xEA\x19\x9F\x4B\x55\xA1\x2A\xE8\x24\x7E\x24\xB1\xFB\x9B\x58\x2F\xE3\xCB\xEB\x42\xEC\x83\x38\x3A\x4F\xEE\xA7\x06\x3B\x6D\x78\xDB\x0F\x3B\xDD\x3C\xFA\xE6\x34\x80\xCF\x26\xAA\x93\xF8\x49\x31\xE0\xD9\xC0\xA6\xFA\x4E\x49\x53\xA5\xEA\xF9\x08\x69\x6E\x52\x03\x5B\x6E\xA6\x57\x4C\xC5\xD7\x4E\x9A\xD1\xE6\xEE\xF8\x50\x9A\x6A\x55\xD7\xBF\x90\xEE\x66\xFD\x00\x9B\x08\x20\xC5\x34\x02\x5B\x84\x91\x2A\x1F\xBE\x96\xA6\x5A\xD5\x36\x12\x3B\x42\x25\xD5\x4D\xBB\x0F\x4D\xBB\x2C\xA2\x49\xA4\x19\x17\xE9\x8E\x07\xD1\xCC\x3D\x37\xFB\x00\xBF\x21\xDD\xCD\x5B\x81\x4D\x86\x97\x62\x38\x82\xD8\x35\xBD\x3B\xC7\x8B\xD8\x49\x22\xE2\x68\x06\xF1\xEF\x87\x7B\xC6\x66\xEA\xB3\x14\xB1\xC8\x3E\x46\xEC\xAA\xA2\x9D\x63\x2B\xF0\xEE\x14\x15\xAB\xA3\x0B\x48\x77\x23\xBB\xE3\x56\xEA\xB1\xB3\x47\xD1\x8C\x25\x7E\x5E\x73\x6F\x71\x4E\x8A\xCA\xD5\xD9\x0D\xA4\xBF\xA9\xCB\xA8\xCF\x76\xB5\x45\x70\x34\x71\x27\x78\xF4\x15\xB5\xDA\x1A\x36\x97\x36\x6C\xC1\x7A\xEA\x9B\xDB\x85\xED\x76\xA9\x81\x8D\x38\x23\x81\xCF\x13\xB7\x01\x5D\x5F\xF1\x6D\xF4\x1A\x31\x99\x91\xC0\x3D\xA4\xBF\xC9\x0D\x6C\x27\x86\x77\xC6\x57\xB1\x76\xDE\x4D\xEC\xCE\x2C\x7D\xC5\x5D\xE8\x83\x39\xB9\xD1\xA4\x7D\xAD\xD0\x33\xB6\x03\xFF\x8C\x6D\x8D\x2B\x43\x33\x09\x3B\xEE\x24\xC5\x7C\xE6\xDE\xE2\x7E\x6A\x74\x24\x4A\xD1\x8C\x25\xED\x3B\xE2\x9D\x63\x2D\x36\xA5\x4F\x9F\xDE\x03\x37\x0C\x9B\x87\x1E\xB9\x2B\x69\x7F\xF1\x28\xDA\x55\x32\xBB\x89\xC0\xE3\xE4\x4B\x82\x06\xF0\x14\xF0\x01",
				"\xF4\x1B\xAA\x15\xED\xC0\x99\xC4\x1D\x73\xD2\x6A\x3C\x8E\x26\xEC\x14\xC6\x78\xE0\x21\xF2\x26\x44\x77\x52\xA8\x23\xEF\xDA\x0C\xD2\x6C\xD8\xD0\x5F\xCC\x43\x9D\xB7\x70\xC6\x01\x0F\x90\x3F\x39\xBA\x13\xE4\x4F\xB0\x65\x91\x75\x37\x0C\xF8\x53\xE0\x11\xF2\xDF\x97\x06\x36\x55\x76\x6C\x68\x8D\x65\xD0\x46\x03\x77\x93\x3F\x49\xBA\x63\x39\x70\x19\xF5\xFC\x9D\x35\x1E\xDB\xB4\xBF\x95\xCD\xE6\x53\xC5\x5D\x68\xC0\xAA\xF0\x46\x60\xEF\xF4\x72\x27\x4B\xCF\x78\x05\x3B\x87\x68\x06\xD5\x7F\xBC\x3E\x02\xB8\x05\xDB\xBD\x31\x77\xBB\xF7\x8C\xEF\x63\xAF\x1F\xA5\x04\xDA\x88\x3D\x4E\x72\x28\xF1\x0C\x36\x21\xE4\xE0\xB0\xDA\xA7\x77\x28\x76\xC8\x57\x8E\xD9\x53\xAD\xC4\xB5\x54\xFF\x83\xB3\x92\xCE\x27\xED\x02\x88\x81\xC6\x42\x2C\xF1\x8F\xA5\x5C\x5B\xB6\x74\x62\x53\x4B\xAF\xC7\x26\xB6\xE4\x6E\xC7\x5D\xC5\x56\xE0\xA3\x41\x6D\x20\x89\x9C\x40\xDA\xA5\x88\x83\x8D\x35\xD8\xC6\xF3\x17\x62\xDF\xCE\xED\x11\x8D\x31\x48\xED\xC0\x21\xC0\x45\xC0\xBF\x63\xEF\xBF\x73\xB7\x57\x7F\xF1\x22\x35\x58\x55\x54\x97\xC7\x8A\x37\x62\xBB\x6D\x94\xE9\x90\xB3\x75\xD8\x4C\xB3\x47\x80\xC7\xB0\x57\x54\x8B\xB0\x79\xC2\x91\x3A\x81\x03\xB1\x0E\x7B\x28\xB6\x95\xEA\x31\x94\x6B\xE4\xF6\x21\xE0\x0C\xE0\xF9\xDC\x17\x12\xAD\x2E\x1D\x18\x6C\x00\xE3\x1F\x81\xF3\x72\x5F\xC8\x10\x6C\x01\x96\x60\xAB\xA3\x96\x36\xE3\x45\x60\x75\x8F\x58\x8F\x75\xF2\x57\xB1\xD3\xE3\x01\xC6\x60\x1D\xB3\x13\xEB\x88\x13\x7A\xC4\x64\x60\xEA\x4E\x51\xE6\x99\x65\x37\x03\x97\x60\x6D\x25\x15\xF4\x61\xD2\xED\x76\xA9\x48\x17\xEB\xD0\x06\x74\xB5\xB1\x2F\x76\x5A\x61\xEE\xA4\x53\xF8\xC4\xCF\xD0\x81\x63\xB5\xD3\x89\x9D\x00\x51\xE4\x51\x6A\x45\xDF\xD1\x85\xED\xE9\x5D\xA6\x11\x7C\x71\x76\x18\xF0\x30\xF9\x93\x51\x31\xB0\x78\x14\x78\x7B\x2F\xF7\x53\x6A\xA8\x13\x5B\xDA\xB6\x81\xFC\x89\xA9\xE8\x3B\x36\x61\x4B\x38\xF5\xAD\x2B\xBF\x63\x7F\x60\x0E\xF9\x93\x54\xD1\x7B\xDC\x81\x1D\xB9\x23\xD2\xA7\x19\xC0\x02\xF2\x27\xAC\xC2\xE2\x69\xE0\xBD\x7D\xDE\x31\x91\x9D\x0C\xC7\x4E\x63\xCF\xB9\x63\x44\xDD\x63\x0D\xF6\x4E\x57\x87\x6A\xCB\xA0\xED\x8E\x8D\x56\xEB\xDD\x71\xBA\xD8\x80\x6D\x1F\x5C\xC7\x65\x98\x12\x64\x22\x96\x54\x45\x5B\x26\x57\xA5\xD8\x08\xDC\x04\xEC\xD9\xE2\x3D\x11\x19\xB0\x3D\xB1\x55\x38\xAB\xC9\x9F\xF0\x55\x89\x55\xD8\xAA\xAC\xC9\x03\xB8\x0F\x22\x43\xB2\x1B\x76\xD4\xCB\x53\xE4\xEF\x00\x65\x8D\x25\xD8\xEB\x3B\xED\x92\x21\xD9\x74\x00\xEF\x03\x6E\x27\xCF\x89\x02\x65\x8B\x2E\xE0\x47\xC0\xC9\xE8\x5D\xAE\x14\xCC\xDE\xC0\xDF\x60\xDF\x2C\xB9\x3B\x4A\xD1\x62\x31\xF0\x19\x60\xAF\x41\xB7\xAE\x48\x42\x6F\xC1\x46\xAF\xEB\xDC\x99\x9F\xC7\x06\xA5\xA6\x53\xAF\xA5\xAB\x52\x21\xED\xC0\xBB\x80\x1B\xC9\x77\xF6\x4F\xCA\x78\x0A\xF8\x07\xAC\xD3\x16\x69\x57\x11\x11\x17\xFB\x01\x7F\x81\xFD\x66\x7E\x89\xFC\x1D\x6E\xA8\xB1\x1E\xF8\x2F\x6C\xBB\x9D\xA9\x8E\xED\x24\x2D\xD0\x63\x4D\x5E\x1D\xD8\xD6\x35\xD3\xB1\x6D\x6B\xA6\x03\xFB\x64\xBD\xA2\xFE\xAD\xC0\x36\x47\x9F\x8B\x1D\x0C\xB6\x00\xD8\x96\xF5\x8A\x6A\x4C\x1D\xB8\x78\x26\x62\x7B\x51\x1D\xC2\x8E\x7D\xA9\xF6\x27\xFD\xAC\xA4\x35\xD8\xC0\x53\xF7\x7E\x5C\x0B\x80\xF9\xD8\xFB\x6F\x29\x08\x75\xE0\xF2\x18\x8B\x3D\xA2\x4E\x69\xC6\xEB\xB1\xCE\xDE\x73\x7F\xAB\x11\xCD\xBF\xD7\x8E\xCD\x1F\x1E\xDD\xFC\x77\x37\x60\xAF\x6F\xB6\x63\x8F\xBC\x5B\xB0\x8E\xB8\xAA\xF9\xE7\x4A\xE0\xD7\xD8\x49\x12\x4B\x9B\xF1\x52\x78\x8D\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\xA4\xF4\xFE\x1F\x9F\x26\x82\x4B\xC1\xE1\x03\xEE\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x4E\x6F\x6E\x65\x87\x13\x00\x00\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\xF0\x00\x00\x00\xF0\x08\x06\x00\x00\x00\x3E\x55\xE9\x92\x00\x00\x00\x06\x62\x4B\x47\x44\x00\xFF\x00\xFF\x00\xFF\xA0\xBD\xA7\x93\x00\x00\x13\x3C\x49\x44\x41\x54\x78\x9C\xED\xDD\x79\xB0\xDE\x55\x7D\xC7\xF1\xF7\x93\x9D\x35\xB9\x06\x08\x8B\x40\x22\x7B\xD9\x77\x50\xA4\x0C\x45\x04\xAC\x12\x60\xB0\x68\x3B\x78\x29\xB8\x8C\x83\x40\xAD\xCB\x50\xA8\xA5\x45\x91\x29\x5A\x8C\x4A\xAB\x32\x2D\xB4\x53\x10\x52\x29\x55\x08\x12\xC1\x22\xB6\x6C\xA1\x94\x7D\x4F\x00\x03\x62\x48\x81\xDC\x10\xB2\xDF\xDC\xA7\x7F\x7C\x9F\x3B\x09",
				"\xE1\x2E\xCF\x7D\xEE\xF7\x7B\xCE\x6F\xF9\xBC\x66\xCE\x24\x86\xEB\xB9\xE7\xFB\x7B\xCE\x79\x7E\xE7\xF7\x3B\x1B\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x00\x8D\xDC\x05\x10\x37\x5D\xC0\x96\xC0\x58\x60\x73\x60\xFC\x46\xFF\xBD\x17\x58\xD6\xFA\x7B\x0F\xB0\x14\x58\x97\xAC\x74\x12\x42\x0D\xB8\xD8\x1A\xC0\xF6\xC0\xFB\x80\x5D\x80\x9D\x81\x6D\x5B\xFF\xD6\xFF\xE7\x96\xAD\xD4\x89\xB7\xB1\x86\xFC\x06\xF0\x0A\xF0\x5A\xEB\xCF\x57\x81\x05\xC0\x7C\x60\x21\x6A\xE8\x85\xA5\x06\x5C\x1C\xDB\x02\xFB\xB7\xD2\xBE\xAD\xB4\x07\x30\x29\x67\xA1\x80\xB5\xC0\x4B\xC0\x63\xC0\xE3\xAD\xF4\x28\xF0\x02\xD0\xCC\x57\x2C\x01\x35\xE0\x5C\xC6\x03\x87\x02\x87\x03\x47\xB4\xD2\x4E\x59\x4B\x34\x72\x4B\x80\xFB\x37\x48\xF7\xB1\xBE\x8B\x2E\x89\xA8\x01\xA7\xD1\x00\xF6\x03\xFE\xA0\x95\x8E\xC6\x9E\x53\xAB\xA4\x17\x78\x10\xB8\x13\xF8\x25\xD6\xA0\xD7\x64\x2D\x91\xC8\x28\x4C\x02\x8E\x03\x66\x01\x2F\x63\xDD\xCD\x3A\xA5\xE5\xC0\x2D\xC0\x67\xB0\xC7\x03\x91\xC2\x9B\x08\xCC\x04\x6E\xC4\x5E\x10\xE5\x6E\x44\x45\x49\xBD\xC0\x5D\xC0\x67\x81\xF7\x74\x7C\x75\x45\x02\x34\x80\x63\x80\x7F\xC4\x9E\x0B\x73\x37\x96\xA2\xA7\xD5\xC0\xCF\x80\x3F\xC2\xBE\xF0\x44\xB2\x98\x82\x75\x0F\x1F\x27\x7F\xA3\x28\x6B\x5A\x02\xFC\x10\x7B\x3F\x20\x92\xC4\x21\xC0\xF5\xD8\x9D\x24\x77\x03\xA8\x52\xBA\x1B\x38\x0D\x18\xD3\xFE\x47\x21\xD2\x9E\x06\xF6\x42\xEA\x16\xF2\x57\xF4\xAA\xA7\x17\x80\xAF\x02\x93\xDB\xFA\x64\x44\x86\x30\x16\xF8\x24\xF0\x14\xF9\x2B\x76\xDD\xD2\x1B\xC0\xC5\x74\x3E\xCB\x4C\x6A\x6C\x0C\x70\x3A\xF0\x34\xF9\x2B\x72\xDD\xD3\x5B\xC0\xE5\xD8\x3B\x07\x91\x61\x7D\x04\x78\x92\xFC\x15\x57\xE9\x9D\xE9\x75\xE0\x02\x60\xC2\xE0\x1F\x9D\xD4\xD9\xEF\x01\x73\xC8\x5F\x51\x95\x86\x4E\xBF\x01\xCE\x44\xB3\x08\xA5\x65\x2A\x70\x35\xB6\xE2\x26\x77\xE5\x54\x6A\x3F\xFD\x17\x1A\x7E\xAA\xB5\x06\xF6\x4D\xBE\x98\xFC\x95\x51\xA9\xB3\xB4\x16\x9B\xAA\xAA\x17\x5D\x35\xB3\x17\xF0\xDF\xE4\xAF\x80\x4A\x3E\xE9\x65\x6C\x0A\xAB\x54\x5C\x03\x9B\x3D\xB5\x9C\xFC\x95\x4E\xC9\x3F\xCD\xC6\x1E\x89\xA4\x82\xA6\x63\x13\xEA\x73\x57\x32\xA5\xD8\xB4\x08\x38\x99\x9A\xA8\xCB\x9B\xBC\x33\x81\xAB\xA8\xDE\x1A\xDC\x0D\xAD\xC4\xC6\x4C\x97\x63\x0B\xEB\x7B\x37\xFA\xEF\xE3\xB1\xF8\x27\x61\xB3\x9C\x36\x4B\x5A\xBA\xF4\xBE\x0F\x7C\x09\x9B\xF2\x5A\x59\x55\x6F\xC0\x9B\x63\x1F\xE4\xA7\x72\x17\x64\x94\xDE\x06\x9E\xC3\xA6\x19\x2E\x00\x5E\x04\x7E\x0B\xFC\xAE\x95\xFE\x0F\x7B\xA1\x33\x12\xE3\xB0\xA5\x7D\xD3\x80\xF7\xB6\xFE\x9C\x8E\xED\xBD\xB5\x0B\xB0\x1B\xB0\xD5\xE8\x8B\x9E\xD5\xC3\xD8\xAA\xA7\xE7\x73\x17\x24\x4A\x95\x1B\xF0\x7E\xD8\xBA\xDC\x3D\x73\x17\x64\x84\xDE\xC4\xB6\xA8\x99\x87\xED\x43\xF5\x18\xD6\x60\xFB\x32\x94\x65\x3B\xEC\x3A\xEE\x0F\x1C\x04\x1C\x49\xF9\xB6\xFE\x59\x86\xBD\xF7\xB8\x21\x77\x41\xA4\x7D\xA7\x51\x9E\x05\xF5\xAF\x61\xAB\x9B\xCE\xC6\x36\xB1\x2B\xFA\x97\xEA\xF6\xD8\xF5\xBD\x0A\x78\x96\xFC\xD7\xAF\x9D\xD4\x87\x4D\xC7\xD4\x4A\xA7\x82\x6B\x00\x97\x60\x1F\x58\xEE\x4A\x33\x58\x5A\x07\x3C\x00\x5C\x84\xDD\xD9\x8A\xDE\x60\x87\xB3\x23\xB6\xD3\xC6\x1C\xEC\x39\x3C\xF7\xF5\x1D\x2A\xCD\x41\xAB\x9C\x0A\x6B\x53\xE0\x26\xF2\x57\x92\xC1\xEE\x00\xF7\x00\xE7\x62\xDD\xD2\xAA\xDA\x0C\x5B\x04\x72\x33\xB0\x8A\xFC\xD7\x7D\xA0\xF4\x34\xB6\xCF\xB6\x14\xC8\x54\xE0\x5E\xF2\x57\x8E\x8D\xD3\x8B\xC0\x5F\x62\x2F\x87\xEA\xA6\x0B\x38\x07\xDB\x9D\x32\xF7\xE7\xB0\x71\x5A\x04\x1C\x1C\x17\xBA\x8C\xC4\x74\x8A\xB5\xEC\xAF\x17\xEB\x09\x7C\x18\x3D\x73\xF5\xDB\x0F\x1B\x0D\x58\x4A\xFE\xCF\xA7\x3F\x2D\x03\x8E\x8F\x0C\x5A\x86\xB7\x0F\x76\x0C\x48\xEE\xCA\xD0\x5F\x21\xBE\x8B\xBA\x67\x43\x99\x8C\x8D\xCD\x2E\x24\xFF\xE7\xD5\xC4\xF6\xAD\xFE\x44\x68\xC4\x32\xA8\xFD\x29\xC6\x42\x84\x1E\xE0\xAF\xB1\x2E\xA3\xB4\x67\x3C\x36\xB9\xE6\x39\xF2\x7F\x7E\xBD\xAD\xB2\x48\x42\x07\x62\x0B\xBC\x73\x37\xDC\x4B\xD0\x4E\x11\xA3\x31\x0E\x6B\x3C\xCF\x93\xF7\xB3\x5C\x87\x0D\xE3\x49\x02\x07\x61\x93\x1D\x72\x7D\xD8\x6B\xB0\xE7\xB9\xAD\xA3\x03\xAD\x91\x09\xC0\x79\xE4\xFD\x52\xEE\xC3\x5E\xBA\x49\xA0\x3D\xC8\xDB\x6D\xBE\x8D\xF2\xCD\xEC\x2A\x93\x29\xC0\xB7\xB0\x2F\xC9\x1C\x9F\x6F\x2F\xF0\xF1\xF0\x28\x6B\x6A\x27\xF2\xBD\xFC\x78\x19\x9B\x7D\x24\x69\xEC\x4B",
				"\xBE\xF5\xDA\xAB\x81\x13\xE2\x43\xAC\x97\xAD\xC9\x33\x6D\xAF\x0F\xDB\xF1\xA1\xCA\xAB\x98\x8A\xAA\x01\x7C\x9A\x3C\x43\x4F\xCB\x81\xF7\xC7\x87\x58\x0F\x13\xC8\xB3\x8E\xF7\x25\xE0\xD8\xF8\xF0\x64\x18\xDB\x01\xB7\x92\xFE\xF3\x7F\x1D\xD8\x35\x41\x7C\x95\xD6\x00\xFE\x85\xF4\x1F\xDE\xB5\x68\x9F\xA5\x22\x69\x00\x5F\x20\xFD\xF4\xCC\x27\xD1\xDC\xE9\x51\xB9\x88\xB4\x1F\xD8\x32\x34\x26\x58\x64\x07\x92\x7E\xEC\x78\x2E\x36\xDC\x25\x23\x74\x22\x69\xB7\x7A\x7D\x02\xBD\x61\x2E\x83\x2D\xB0\xBD\xAF\x52\x36\xE2\x2B\x92\x44\x56\x21\x3B\x61\xBB\x4C\xA4\xFA\x80\xB4\xCC\xAC\x5C\x1A\xD8\x01\x68\xA9\xBE\xE0\xFB\xD0\x28\x44\xDB\x26\x62\xBB\x51\xA4\xFA\x60\x2E\x45\x8B\x0E\xCA\xEA\xA3\xD8\x63\x4F\x8A\xBA\xB2\x04\xDB\x6A\x48\x86\x31\x8B\x34\x1F\xC8\x5A\xE0\xAC\x44\x31\x49\x9C\x83\xB1\xE5\x81\x29\xEA\xCC\x43\xE8\x6C\xA6\x21\x1D\x47\x9A\xDD\x34\xDE\xC6\x0E\x31\x93\x6A\x98\x01\x3C\x43\x9A\x46\x7C\x59\xA2\x98\x4A\xA7\x0B\x9B\xF1\x14\xFD\x01\x2C\x45\x83\xF4\x55\x34\x0D\x7B\x11\x19\x5D\x7F\x7A\x81\xA3\x12\xC5\x54\x2A\xD7\x13\x7F\xF1\x7B\x80\x23\x52\x05\x24\xC9\x6D\x0D\x3C\x4A\x7C\x3D\x5A\x80\xBD\x0D\x97\x96\x8F\x90\xE6\xCE\x7B\x58\xAA\x80\x24\x9B\xA9\xA4\x69\xC4\xDF\x49\x15\x50\xD1\x6D\x8A\x6D\x58\x1E\x79\xB1\x57\x00\xBF\x9F\x2A\x20\xC9\x6E\x1B\xE2\x9F\x89\xD7\xA1\xDE\x1C\x00\x7F\x47\xEC\x85\x5E\x83\x0D\x37\x48\xBD\xCC\xC0\x4E\xAF\x88\xAC\x5B\x0F\x51\xF3\x59\x5A\xFB\x62\x2F\x05\x22\x2F\xF2\x67\x92\x45\x23\x45\x73\x00\xF1\xE3\xC4\xE7\x25\x8B\xA6\x80\xE6\x12\x7B\x71\xBF\x95\x2E\x14\x29\xA8\x93\x88\xBD\x49\xBC\x49\x4D\x8F\x34\x3D\x89\xD8\xC6\x3B\x07\x18\x9B\x2C\x1A\x29\xB2\xAF\x10\x5B\xD7\xAE\x4C\x17\x4A\x31\x8C\x03\x9E\x22\xEE\x82\xBE\x88\x9D\xBC\x27\x02\x36\x77\xFA\xDF\x89\xAB\x6F\xAB\xB1\xD3\x1C\x6B\xA3\x9B\xB8\x8B\xB9\x0A\x38\x24\x59\x24\x52\x16\x5B\x10\x7B\x00\xC0\x75\xE9\x42\xC9\x6B\x1C\xB1\xDB\x88\x5E\x90\x2E\x14\x29\x99\x83\x89\xDB\x30\xAF\x17\xD8\x2B\x5D\x28\xF9\x9C\x45\x5C\xE3\xBD\x93\xF2\x9F\xF6\x27\xB1\x22\x37\x89\xA8\xFC\x5D\x78\x2C\x30\x9F\x98\x8B\xD7\x83\x1D\x75\x29\x32\x94\xB1\xD8\x49\x91\x51\x77\xE1\x4A\x6F\x0A\x71\x1A\x71\xDF\x7E\x9F\x4B\x18\x87\x94\xDB\x1E\xC4\xED\xAF\xF5\x83\x84\x71\x24\x17\xB5\xD7\xEF\xFD\x68\x51\xBE\x8C\xCC\xA5\xC4\xD4\xC5\x15\xC0\x56\x09\xE3\x48\xE6\x30\x62\x2E\xD8\x5A\x60\xEF\x84\x71\x48\x35\x4C\x22\xEE\x65\xEA\x5F\x24\x8C\x23\x99\xA8\xED\x61\xAF\x4A\x19\x84\x54\xCA\x29\xC4\xD4\xC9\x57\xA8\xD8\x1C\xE9\xC9\xD8\x6E\xF7\xDE\x17\xEA\x2D\x6C\x21\xB7\x48\xA7\xEE\x24\xA6\x11\x57\x6A\xC7\x97\xCF\x13\x73\x91\x2E\x4A\x19\x84\x54\xD2\xA1\xC4\xD4\xCD\x9B\x52\x06\x11\xED\x21\xFC\x2F\xD0\xEB\x68\x57\x04\xF1\x11\x71\x74\xCB\x1A\x6C\x5D\x72\xE9\xED\x45\xCC\x37\xDC\x85\x29\x83\x90\x4A\x8B\xBA\x0B\x57\x62\xA9\xE1\xD7\xF0\xBF\x30\x4B\xD1\xD9\x45\xE2\xEB\x17\xF8\xD7\xD3\x5F\x27\x8D\x20\x48\xC4\x4E\x81\xDF\x4E\x1A\x81\xD4\xC1\x89\xF8\xD7\xD3\x75\xC0\xF6\x29\x83\xF0\xB6\x27\xFE\x17\xA5\x17\x98\x9E\x30\x06\xA9\x87\x06\x31\x4B\x5C\xCF\x8D\x2C\x74\xF4\xEC\xA5\x3F\x0C\xC8\xF3\x76\xEC\xEC\x5E\x11\x4F\x4D\x62\xA6\x41\x7E\x2C\x20\xCF\x64\x22\xC6\xD8\x4E\x49\x1A\x81\xD4\xC9\x54\xFC\xE7\x48\xAF\xC4\x76\x5E\x2D\x9D\xCD\xF0\xBF\x18\x8B\x80\xF1\x29\x83\x90\xDA\xB9\x11\xFF\x9B\xCE\x09\x51\x85\x8D\xEC\x42\x1F\x83\x9D\x34\xE8\xE9\x27\xD8\xDC\x67\x91\x28\xD7\x07\xE4\x79\x7C\x40\x9E\xE1\x2E\xC7\xFF\x9B\xEC\xE8\xA4\x11\x48\x1D\x4D\xC4\x86\x29\x3D\xEB\xED\x43\x49\x23\x70\x72\x37\xFE\xDD\x67\xED\x32\x29\x29\x5C\x87\x6F\xDD\x5D\x0B\x6C\x1E\x51\xD0\xA8\x2E\xF4\x78\xFC\x37\x96\xBB\x1D\x1B\x57\x13\x89\x76\x9B\x73\x7E\xE3\xB0\xD9\x5E\xEE\xA2\x1A\xF0\x01\xF8\xBF\x79\x9B\xEB\x9C\x9F\xC8\x60\xEE\xC0\xEE\x9C\x9E\x8E\x74\xCE\x0F\x88\x6D\xC0\x9E\x9A\xD8\x45\x15\x49\x61\x31\xF0\x88\x73\x9E\x07\x39\xE7\x07\xC4\x35\xE0\xFD\x9C\xF3\x7B\x1A\x5B\x7D\x24\x92\x8A\xF7\x3C\xE6\x90\x5D\x63\xCA\xD2\x80\xEF\x71\xCE\x4F\x64\x38\xF7\x39\xE7\xB7\x1B\xB0\x89\x73\x9E\x61\x0D\x78\x1F\xE7\xFC\xEE\x77\xCE\x4F\x64\x38\xDE\x0D\x78\x2C\xB6\x1B\xA6\xAB\x88\x06\xDC\x85\xFF\xB9\x44\xDE\xCF\x23\x22\xC3\x59\x08\xBC\xE1\x9C\xE7\xAE\xCE\xF9\x85\x34\xE0\xE9\xCE\xF9\xAD\xC3\x9E\x81\x45\x52\x7B\xC2\x39\xBF\xE9\xCE\xF9\x95\xA2\x01\xCF\xC7\x26\x84\x17\xC1\x04\xE0\x0C\xE0\x06\xAC\x5C\x6B\x5B\x69\x7E\xEB\xDF",
				"\xCE\x68\xFD\x4C\x2E\x2A\x9F\xAF\xC2\x37\xE0\x08\x17\xE0\x3B\x8B\x65\x4E\xDA\xE2\x0F\xEA\x34\xAC\x5B\x35\x5C\x79\x17\xB6\x7E\x56\xE5\x2B\x57\xF9\x06\xE2\x5D\x97\x6F\x4D\x5B\xFC\xCE\x5C\x86\x6F\xD0\xDF\x4F\x5B\xFC\x77\x19\x03\xCC\x62\xE4\xE5\x9E\x45\x9A\xD3\x22\x54\xBE\x38\xDE\xFB\x46\x3F\x98\xB6\xF8\x9D\xF9\x11\xBE\x41\x7F\x39\x6D\xF1\xDF\xA5\x93\xCA\xB7\x61\x25\x54\xF9\x8A\x5D\xBE\xA1\x1C\x48\xE7\x65\x1F\x28\xBD\x90\xB6\xF8\x9D\xF1\x3E\x09\xFD\xCC\xB4\xC5\x7F\x07\x8F\xC3\xD8\x22\xBB\x83\x2A\x5F\xAC\x1D\x86\x28\x57\x27\xA9\x27\x6D\xF1\x3B\xF3\x2B\x7C\x83\xCE\xB5\xC3\xFD\x04\xEC\x1B\x73\xB4\xE5\x7F\x09\xFF\x75\xD1\x2A\x5F\x1A\x9B\xB4\x51\xBE\x91\xA4\x3E\x9C\x8F\x5C\x89\x78\xC6\xF0\x9E\x6D\xE2\x3D\x16\xD7\xAE\x53\x81\x19\x0E\xF9\xEC\x0C\xCC\x74\xC8\x67\x63\x2A\x5F\xBC\x95\xF8\x8E\x80\x34\x70\x5E\xE4\x13\xD1\x80\xBD\xBF\x2D\x57\x38\xE7\xD7\x2E\xCF\xBD\xB7\x4E\x75\xCC\xAB\x9F\xCA\x97\x86\x77\xFD\x73\xDD\x12\xAA\x0C\x0D\x78\x8D\x73\x7E\xED\xF2\x5C\xBF\x19\xB1\x16\x54\xE5\x4B\x63\xB5\x73\x7E\xAE\xED\x23\xA2\x01\x7B\x6F\x3A\x97\x6B\x0F\xAC\xED\x0A\x9A\x57\x44\x9E\x75\x2C\x5F\xBB\xBC\x6F\x20\xAE\x13\x55\x22\x1A\x70\x9F\x73\x7E\x0D\xE7\xFC\x72\xFC\xDE\x88\x18\x54\xBE\x34\xBC\xDB\x88\x6B\xFB\x88\x68\xC0\xDE\x77\xCC\x5C\x53\xEB\x5E\x2B\x68\x5E\x11\x79\xD6\xB1\x7C\xED\xF2\x7E\x24\x74\xED\x92\x47\x34\xE0\x42\x77\x39\x46\xE0\xE1\x82\xE6\x15\x91\x67\x1D\xCB\xD7\x2E\xEF\xFA\xE7\xDA\x3E\x22\x1A\xB0\xF7\x43\xFF\x64\xE7\xFC\xDA\xF5\x53\xC7\xBC\xFE\xC3\x31\xAF\x7E\x2A\x5F\xBC\x06\xFE\x67\x50\xE7\x7A\x29\xDB\xB6\xB9\xF8\x0E\x7E\xE7\x3A\x4A\x65\x33\x6C\x2B\xDB\xD1\x96\x7F\x51\x2B\x2F\x95\xAF\x58\xE5\x6B\xC7\x94\x36\xCB\xD8\x6E\x5A\x83\xF3\xF3\x7C\xC4\x1D\xD8\x7B\xE2\xC5\x54\xE7\xFC\xDA\xB5\x1C\xB8\xD8\x21\x9F\x8B\x5B\x79\x79\x53\xF9\xE2\x79\x6F\x4C\xB1\x04\x6B\xC8\x85\xF6\x3D\x7C\xBF\xB5\x2E\x49\x5A\xFA\x77\xFB\x31\x9D\x97\xFD\xC7\x2A\x5F\xE1\xCB\x37\x94\x0F\xD2\x79\xD9\x07\x4A\x4F\xA6\x2D\x7E\x67\x2E\xC1\x37\xE8\x6B\x53\x16\x7E\x00\x13\x80\xD9\x8C\xBC\xDC\xB3\x49\xF3\x02\x4E\xE5\x8B\x73\x26\xBE\x75\xD9\x7B\xA7\xCB\x10\xE7\xE0\x1B\xF4\x5D\x69\x8B\x3F\xA0\x06\xF0\x05\xDA\x3B\x33\x67\x69\xEB\x67\x53\x8E\x5D\xAA\x7C\x31\xFE\x0A\xDF\xBA\x7C\x43\xDA\xE2\x77\xE6\x78\x7C\x83\x5E\x94\xB6\xF8\x43\xEA\x02\xBE\x88\x7D\x93\xAE\x60\x7D\x19\x57\xB4\xFE\xED\x8B\xAD\x9F\xC9\x45\xE5\xF3\x35\x9A\xEE\xFF\x40\xE9\x9B\x69\x8B\xDF\x99\xDD\xF1\x0D\xBA\x09\x6C\x9D\x34\x82\xF6\x75\x51\xAC\x0A\xB7\x31\x95\x6F\x74\x9E\xC0\xB7\x1E\x7F\x36\x6D\xF1\x3B\x33\x09\xDB\x49\xD2\x33\xF0\x63\x93\x46\x20\x62\xCF\xDF\x6B\xF0\xAD\xC7\x1F\xF6\x2E\x64\xC4\x30\xD2\x2A\x6C\x11\xB6\xA7\x9C\xAB\x51\xA4\x9E\xF6\xC7\x7F\x61\xCE\x33\xCE\xF9\x85\x6D\x1A\xE6\xBD\x1D\x67\xC8\xC9\x6E\x22\x43\xF8\x80\x73\x7E\x4B\xB1\x1D\x37\x5D\x45\x35\xE0\xC7\x9C\xF3\x3B\x92\x62\xBC\x95\x94\xFA\x38\xC2\x39\xBF\x27\xB1\x6E\xB4\xAB\xB2\xDC\x81\xB7\xC1\xFF\xBC\x25\x91\xC1\x34\x80\x63\x9C\xF3\x7C\xDC\x39\x3F\x20\xAE\x01\xCF\x0B\xC8\xD3\xFD\x05\x80\xC8\x20\x0E\x04\xA6\x39\xE7\x19\xB2\x27\x74\x54\x03\x7E\x11\xFF\xF1\xDB\x13\x9C\xF3\x13\x19\x4C\xC4\xCD\xC2\xFB\xB4\xC3\x70\x37\xE1\xFB\x0A\x7E\x0D\xFE\x93\xCB\x45\x06\x72\x3F\xBE\x75\xF7\x4D\x82\x6E\x96\x91\x47\x57\xDC\xEB\x9C\xDF\x78\xE0\x64\xE7\x3C\x45\x36\xB6\x33\x70\x98\x73\x9E\xF7\xE2\xBF\xD5\x14\x10\xDB\x80\x7F\x19\x90\xE7\xE9\x01\x79\x8A\x6C\xE8\x74\xFC\x47\x3C\xEE\x72\xCE\x2F\x89\x06\xF0\x2A\xBE\x5D\x91\xB5\xC0\xF6\x29\x83\x90\xDA\x79\x04\xDF\x3A\xDB\x04\xF6\x4E\x1A\x81\xA3\x7F\xC6\xFF\x62\x5C\x98\x34\x02\xA9\x93\xC3\xF1\xAF\xAF\x2F\x47\x16\x38\xFA\xF8\xC6\xDB\x03\xF2\x3C\x9B\xFC\xC7\x4E\x4A\x35\x9D\x1D\x90\xE7\xDC\x80\x3C\x93\xD9\x02\x3B\x5B\xC6\xFB\x5B\xED\xA3\x29\x83\x90\x5A\x78\x0F\xF0\x36\xFE\x75\x35\xD7\xE1\x7C\x6E\x7E\x8A\xFF\x45\xF9\x55\xCA\x00\xA4\x16\x2E\xC6\xBF\x9E\x2E\x21\xFF\xAE\x22\xA3\xF6\x27\xF8\x5F\x98\x26\x70\x70\xCA\x20\xA4\xD2\x26\xE2\xFF\xC2\xB5\x09\x5C\x93\x32\x88\x28\x5B\x12\xD3\x8D\xF6\xDC\x77\x58\xEA\xED\x5C\x62\x6E\x32\x27\xA6\x0C\x22\xD2\xBF\x12\x73\x81\xBC\x07\xDC\xA5\x7E\x26\x01\xAF\xE0\x5F\x37\x5F\xC5\xF9\x30\xEF\x9C\x8E\x21\xA6\x01\xFF\x3C\x61\x0C\x52\x4D\x7F\x46\x4C\xDD\xFC\x7A\xCA\x20\xA2\x35\x80\xE7\x88\xB9\x50\x5A\xE4\x20\x9D\xEA",
				"\x02\x5E\xC7\xBF\x4E\xF6\x01\xBB\x24\x8C\x23\x89\xAF\x10\xD3\x80\x9F\xA4\x42\x5D\x15\x49\xCA\xFB\x10\x82\xFE\x74\x47\xCA\x20\x52\xE9\x22\x66\x9C\xAD\x09\x9C\x9F\x30\x0E\xA9\x86\x7D\xB0\xA9\xB9\x11\xF5\xB1\xF4\x63\xBF\x83\x89\xFA\xC6\x7B\x1B\x98\x91\x30\x0E\x29\xB7\x31\xC0\x3D\xC4\xD4\xC5\x67\xA8\xF0\x4C\xC1\x19\x40\x2F\x31\x17\xEE\xB6\x84\x71\x48\xB9\x9D\x4F\x4C\x1D\x6C\x62\x27\x93\x54\x5A\x27\xE7\xE4\xB4\x9B\x3E\x91\x30\x0E\x29\xA7\x5D\x80\x65\xC4\xD4\xBF\x57\xB1\x61\xA9\x4A\xDB\x1B\xFF\x8D\xDF\xFB\xD3\x4B\xD8\xAC\x1A\x91\x81\x8C\xC3\x16\xD7\x47\xDD\x40\xCE\x4B\x17\x4A\x5E\xD7\x11\x77\x11\xCF\x48\x18\x87\x94\xCB\x25\xC4\xD5\xBB\x97\xA9\xC1\xDD\xB7\xDF\xEE\xC4\xBD\x01\xBC\x31\x61\x1C\x52\x1E\xC7\x12\xF7\xFE\xA5\x09\x7C\x3E\x5D\x28\xC5\xF0\x23\x62\x2E\xE4\x0B\x29\x83\x90\x52\xD8\x11\x58\x4C\x5C\xE3\x7D\x9E\x0A\xAC\x3A\x1A\xA9\x69\xB4\x77\x5E\xEC\x48\xD3\x8A\x94\x41\x48\xE1\x4D\xC2\x7F\x97\xC9\x8D\x53\x6D\x37\x5B\xFC\x32\xFE\x17\x73\x79\xD2\x08\xA4\xC8\x1A\xC4\x2D\xA4\xE9\x4F\x11\x9B\x37\x96\xC6\x34\xD4\x85\x96\x38\x97\x13\xDB\x78\xD7\x02\xFB\x26\x8B\xA6\x80\xBA\xF1\xBF\xA8\xB3\x53\x06\x20\x85\x15\xB5\xC6\x77\xC3\x74\x45\xB2\x68\x0A\x6A\x0E\xFE\x17\xB5\x3B\x65\x00\x52\x48\xDD\xD8\x8A\xA0\xC8\xC6\xBB\x00\xD8\x34\x51\x3C\x85\xD4\x05\xAC\xC6\xF7\xA2\xAE\x6E\xE5\x2B\xF5\x75\x3A\xB1\xC3\x45\x4D\xEC\xCB\xE1\x43\xA9\x02\x2A\xAA\x6E\xFC\x2F\xEC\x9C\x94\x01\x48\xE1\x7C\x92\xB8\xF9\x05\x1B\xA6\x7F\x4A\x15\x50\x91\xA9\xFB\x2C\x9E\x3E\x4D\xDC\x14\xDD\x0D\xD3\x7C\x6C\xBB\xE4\x5A\x53\xF7\x59\x3C\x7D\x95\xF8\x67\xDE\x26\x76\x77\x3F\x22\x51\x4C\x85\xD6\x8D\xFF\xC5\x55\xF7\xB9\x7E\xC6\x02\x7F\x4F\x7C\xC3\xED\x4F\x5F\x4B\x13\x56\xF1\xA9\xFB\x2C\xA3\xB5\x25\x70\x0B\xE9\x1A\xEF\x1D\xD8\x17\x46\xED\x4D\xC1\xBF\xFB\xAC\xC3\xBF\xEB\x65\x77\x6C\x2F\xB4\x54\x8D\x77\x21\xB0\x75\x92\xC8\x4A\xA0\x1B\xFF\x0B\xAC\xEE\x73\x7D\x9C\x4A\xCC\x1C\xFA\xC1\xD2\x2A\xE0\xD0\x24\x91\x95\x84\xBA\xCF\xD2\x89\x49\xC0\x55\xA4\x6B\xB8\xFD\x29\xE2\xC4\xC2\xD2\xD2\xDB\x67\xE9\xC4\xBE\xC0\x63\xA4\x6F\xBC\xDF\x4C\x11\x5C\x99\x9C\x85\xFF\x45\xBE\x35\x69\x04\x92\xD2\x38\x6C\x88\x68\x15\xE9\x1B\xEF\x6C\x2A\xBC\xBB\x64\xA7\xD4\x7D\x96\x76\x1D\x0C\xFC\x2F\xE9\x1B\x6E\x13\xF8\x35\x35\xDA\x1E\xA7\x5D\x7A\xFB\x2C\xED\x98\x02\xCC\x22\x7E\x3E\xF3\x60\xE9\x11\xF4\x48\x36\xA0\x6E\xFC\x2F\xB6\xDE\x3E\x57\xC7\x38\xE0\x73\xC0\x6B\xE4\x69\xB8\x4D\xE0\x09\x60\xAB\xE8\x40\xCB\x4A\xDD\x67\x19\x48\x03\x1B\x1A\x7A\x86\x7C\x0D\xB7\x89\xED\x6B\xB5\x5D\x70\xAC\xA5\x55\xD6\xB7\xCF\x93\x81\xE3\x80\x8B\xB0\x03\xC5\xE7\x63\xF3\x61\xD7\xB6\xFE\x7E\x03\xB6\x8D\x6D\xED\x36\x34\x73\xD0\x00\x3E\x06\x3C\x48\xDE\x86\xDB\x04\x9E\x06\x76\x88\x0D\xB7\xDC\xBA\xF1\xBF\xE8\xDE\xDD\xE7\xF1\xC0\x21\xD8\xF6\xA0\xD7\x02\x4F\xD1\xFE\xEA\x96\xDF\x01\x17\xA2\x67\xA7\x76\x8C\x03\x3E\x0E\x3C\x4C\xFE\x86\xDB\x04\x1E\xC5\xB6\x76\x92\x21\x14\xB1\xFB\xBC\x2B\xB6\x7E\xF4\x3B\xD8\x6E\xFD\x2B\x1D\xCA\xB4\x0C\xB8\x12\xD8\x6D\x94\x65\xAB\xA2\xC9\xC0\x97\xB0\xD3\x33\x72\x37\xDA\xFE\x34\x0F\xBD\x04\x1D\x56\x11\xBA\xCF\x5B\x01\x27\x61\x3B\xF3\xDF\x46\xCC\xA1\xCE\x1B\xA6\x3E\x6C\xF2\xFB\xA9\xD8\x9D\xBD\xCE\x8E\xC4\x16\xC0\x47\x1D\x2D\xDB\x69\xFA\x39\x5A\xD7\xDB\x96\x6E\xFC\x2F\xFE\x50\xDD\xE7\x49\x58\xA5\x39\x1F\x3B\xC2\x65\x7E\xC0\xEF\x1F\x49\x5A\x8C\x1D\xAB\x5A\xA7\x75\xA4\x33\xB0\x47\x8A\xC7\xC9\xDF\x50\x07\x4A\x57\xA3\x43\xE1\xDB\x16\xD9\x7D\x1E\x03\xEC\x05\x7C\x0A\x9B\x27\xFB\x3F\xD8\xD8\x70\xEE\x0A\x32\x58\x9A\x0F\xFC\x2D\xF0\x7E\xAA\x37\xCB\x67\x0F\x6C\x9F\xEF\xFB\x49\xB3\xB8\xBE\x93\xD4\x87\xBD\x90\x94\x36\x45\x74\x9F\x9B\xD8\x22\xEE\x3B\x81\x9E\x80\xBC\x53\xA5\x45\xC0\x35\xC0\x1F\x03\xDB\x76\x7A\x81\x33\xDA\x1C\x7B\x2C\xF9\x36\xF0\x2C\xF9\xAF\xE7\x70\x69\x29\x30\x33\xE4\x4A\x64\xD4\x08\xCE\xBF\x1B\xAB\xA4\x32\xB4\x26\xB6\xBE\xF5\x1E\xE0\xBE\x56\x7A\x2E\x6B\x89\xDE\x6D\x3B\xE0\x70\xEC\xF1\xE4\x03\xAD\xBF\x97\xA5\x1B\xFA\x2C\x70\x0A\x36\x5C\x54\x29\xD1\x0D\x78\x0E\xF6\x2D\x2D\x23\xD7\x83\x0D\x71\x3C\xD6\x4A\xCF\x61\x7B\x11\xFF\x36\xF8\xF7\x4E\xC5\x0E\xC1\xDE\x1D\x5B\x05\xD4\x9F\xDE\x1B\xFC\x7B\xA3\xDC\x8C\xDD\x48\xDE\xCA\x5C\x8E\x10\x91\x0D\xB8\x0B\xEB\x26\x6A\x92\x83\xAF\x15\xC0\x8B\xD8\xD8\xF3\xAB\xAD\xB4\x04\x6B\xF0\x3D\x58",
				"\x57\xB1\x7F\xFC\xBA\xA7\xF5\xFF\xD9\x82\xF5\x77\xCB\x2E\x6C\x48\x67\x72\xEB\xEF\x3B\x00\xDB\xB4\xFE\xDC\x19\x9B\x8B\x5C\x05\x2B\x81\x3F\x07\xFE\x21\x77\x41\xCA\xAA\x9B\xFC\xCF\x3D\x4A\xF5\x4C\x4F\x00\xFB\x50\x03\x91\x6F\x42\x4F\x0F\xCC\x5B\x64\x20\xEB\xB0\x97\x6A\x87\x62\x8D\xB8\xF2\xA2\xBA\xD0\xEA\x3E\x4B\x6A\x4F\x03\x7F\x8A\x0D\x63\xD5\x46\xD4\x1D\xF8\x64\xD4\x78\x25\x8D\xD5\xC0\xD7\x81\x83\xA8\x59\xE3\x85\xB8\x61\x00\x75\x9F\x25\x85\x3B\xB0\x63\x44\x8B\x36\xE4\x96\x4C\x44\x17\x5A\xDD\x67\x89\xB6\x10\x9B\xF5\x55\xFB\xB3\xA0\x23\xEE\xC0\xEA\x3E\x4B\x94\x25\xC0\xE5\xC0\x77\xB1\x8D\xEE\x6A\x2F\xA2\x01\x6B\xE2\x86\x78\x5B\x89\x4D\x9F\xBD\x0C\x78\x33\x73\x59\x0A\x25\xA2\x01\x1F\x12\x90\xA7\xD4\xD3\x0A\xE0\x07\xC0\x15\xD8\x63\x99\x6C\x24\xE2\x19\x78\x05\xB0\x49\x40\xBE\x52\x1F\x4B\x81\x1F\x62\x63\xBA\x8B\x33\x97\xA5\xD0\xCA\x32\x19\x3D\xB7\xE5\xC0\x43\xD8\xFE\x4D\x87\x03\x47\xE5\x2D\x4E\x65\x2D\xC0\x9E\x6F\xAF\xC1\x76\x37\x91\x0C\x5E\x20\xFF\x54\xBA\xD1\xA4\x5E\x6C\x11\xC1\xD5\xC0\x39\xC0\x7E\xBC\xFB\x58\xC9\x03\xB0\xAE\xDD\xB2\x02\x94\xB7\xEC\x69\x1D\xB6\x3B\xC6\x4C\xAA\xB7\x46\xBA\x94\x6E\x24\x7F\xA5\x18\x49\x5A\x08\xFC\x1B\xB6\x5F\xD3\xD1\xD8\x3A\xD7\x76\x6D\x89\x6D\x82\x57\x84\x9D\x15\xCB\x96\x5E\x01\xFE\x06\x5B\x40\x21\x05\x72\x06\xF9\x2B\xC7\x60\xA9\x07\xDB\x08\xE0\x1B\xD8\x70\x97\xE7\x3E\xC0\x7B\x02\x97\x52\xFE\x1E\x48\x64\x7A\x03\xEB\xD9\x1C\x8B\x0E\xCB\x76\x11\xF1\x12\x6B\x22\xB6\x80\x3A\xF7\x37\xEB\x5A\x6C\x1D\xED\x03\xD8\xEE\x83\xF3\xB0\x72\xF5\x05\xFF\xDE\x06\xF6\x9C\x3C\xB3\x95\xF6\x08\xFE\x7D\x45\xB7\x18\x3B\x80\xEE\x66\xE0\x17\xD8\x96\x47\xE2\x24\x6A\x31\xC3\x69\xC0\x4F\x82\xF2\x1E\xCC\x02\xDE\xD9\x58\x1F\xA6\x18\x83\xFD\x7B\x61\x1B\x98\x7F\x08\xDB\xC9\xA2\xEA\x87\x66\xF5\x61\xEF\x10\xE6\x02\x3F\xC3\x3E\x93\xE8\x2F\xCD\xDA\x8A\x5C\xD0\x3F\x0B\x38\x2F\x28\xEF\x37\x58\xDF\x50\xFB\xD3\xEB\x41\xBF\xCB\xD3\x26\xC0\x07\xB1\xD3\x1E\x8E\xC2\x26\xE0\x4F\xCC\x5A\xA2\xD1\xEB\xC3\x8E\x45\xB9\x1B\xF8\x4F\xE0\x2E\xEC\xF3\x91\x04\x22\x1B\xF0\x18\x6C\x93\xF3\xD1\x36\xE2\x55\xD8\xDD\x74\xC3\xC6\x3A\x7F\x94\x79\x16\xC5\x44\xEC\x18\xCD\x23\x80\xC3\x80\xFD\xB1\x4D\xE1\x8B\xFC\x7C\xB8\x10\xDB\x2E\x76\x1E\xB6\xFA\xE7\x01\x6C\xDC\x56\x32\x88\xDE\x13\x0B\xAC\x3B\x7D\x25\xB0\x63\x1B\x3F\xDB\x87\x3D\xA7\x6E\xD8\x58\x1F\xC5\x9E\x67\xEB\x62\x13\x60\x6F\x6C\xF8\x6A\x37\xEC\x04\x89\x5D\xB1\x7D\xAA\x52\x6D\x44\xBE\x0A\x7B\x24\xE9\x4F\xCF\x63\x0B\xE4\x1F\x67\xFD\x36\x3D\x52\x00\x29\x1A\x30\xD8\xE2\x86\x53\xB1\x97\x3A\x87\xB0\xFE\x05\xD7\x6F\xB0\xDD\x18\xE7\x61\xDF\xE4\x0F\xA2\x6F\xF3\xA1\x74\x61\x6F\xCE\xB7\x6F\xFD\x39\x8D\xF5\xFB\x5B\x4D\xC1\x86\xB5\x36\x6B\xFD\xEC\x98\xD6\xBF\x83\x6D\xE8\xB6\xAE\xF5\xF7\x95\xAD\xFF\xBD\xB4\x95\x7A\xB0\x23\x3D\x5F\xC3\x36\xCC\x5B\xDC\x4A\xCD\xD8\x50\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x44\x04\xFE\x1F\x5E\x25\x15\x9E\xA9\x3B\xF3\x73\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82\x03\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x51\x75\x65\x73\x74\x69\x6F\x6E\x33\x16\x00\x00\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\xF0\x00\x00\x00\xF0\x08\x06\x00\x00\x00\x3E\x55\xE9\x92\x00\x00\x00\x06\x62\x4B\x47\x44\x00\xFF\x00\xFF\x00\xFF\xA0\xBD\xA7\x93\x00\x00\x15\xE8\x49\x44\x41\x54\x78\x9C\xED\x9D\x79\x94\x5E\x55\x91\xC0\x7F\xDD\xE9\x74\x27\x24\x99\x24\x24\x24\x01\x04\x12\xC2\xA2\xC8\x8E\x80\x4A\x10\xC4\x1C\x81\x19\x40\x90\x55\x87\x51\x30\x80\x30\xB8\xB0\x88\xCC\xA8\xA3\xEC\xA2\x28\x43\x10\x8F\xE0\x20\x8B\x23\xBB\x38\x32\x80\x30\x38\x20\x83\x10\x43\x34\x10\x02\x61\x4B\x48\x37\xCB\x91\x25\x1B\x09\xD9\x3B\xC9\x37\x7F\xD4\xD7\xA6\xE9\x74\x7A\xFB\xAA\xEA\xBE\xA5\x7E\xE7\xD4\x49\x0E\xC6\xFB\xDD\xAA\x5B\xF5\xDE\x7D\xF7\xD6\xAD\x0B\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x90\x96\xBA\xD4\x1D\x08\x7A\xCC",
				"\x08\x60\x6C\x55\xB6\x01\x36\xAF\xFE\xB7\x11\xC0\xC8\xEA\x9F\x4D\xC0\xD0\xEA\xBF\x6F\x04\x06\x55\xFF\xBE\x0C\x58\x5D\xFD\xFB\xBB\xC0\x2A\x60\x41\x07\x79\x13\x68\x69\x27\x0B\xAD\x14\x09\xF4\x88\x00\xCE\x1E\xA3\x80\x5D\xAB\xB2\x4B\xF5\xCF\xED\x81\x21\xCE\xFD\x58\x02\xCC\x06\x9E\xAD\xCA\xCC\xAA\xBC\xE3\xDC\x8F\xA0\x0B\x22\x80\xD3\xD2\x0F\xF8\x20\xB0\x1F\x30\xA1\x2A\xE3\x92\xF6\xA8\x7B\xDE\x04\xA6\x03\x8F\x03\x4F\x00\xD3\x58\xFF\x76\x0F\x9C\x89\x00\xF6\x67\x07\xE0\x50\xE0\x10\x60\x7F\xD6\x4F\x73\xF3\xCA\x52\xE0\x31\xE0\x01\xE0\x41\x60\x4E\xDA\xEE\x04\x81\x2E\xFD\x80\x4F\x02\xD7\x20\xCE\x5D\x29\xB8\xCC\x06\xAE\x06\x0E\x00\xEA\x15\xEC\x17\x04\xEE\xD4\x23\xD3\xE1\xC9\xC0\x5F\x49\x1F\x54\xA9\x64\x1E\xF0\x4B\x60\x22\x11\xCC\x41\x0E\xD8\x1A\xB8\x00\x78\x8D\xF4\xC1\x93\x35\x79\x15\xF8\x1E\xF0\x81\xBE\x1A\x37\x08\x2C\x68\x00\x8E\x02\xEE\x07\xD6\x92\x3E\x50\xB2\x2E\x6B\x80\xFB\x80\x23\x91\xCF\x8B\x20\x48\xC2\x60\xE0\x34\xE0\x25\xD2\x07\x45\x5E\xA5\x19\x38\x1F\x18\xD6\x4B\xDB\x07\x41\x9F\xD9\x12\xF8\x01\xB0\x88\xF4\x01\x50\x14\x59\x04\x5C\x8E\x24\xA7\x04\x81\x09\x9B\x21\x4E\xB6\x9C\xF4\x0E\x5F\x54\x59\x05\x5C\x47\x04\x72\xA0\xC8\x08\x64\x61\x6A\x09\xE9\x1D\xBC\x2C\xB2\x0C\x59\xC1\x1F\xDD\xFD\xF0\x04\x41\xE7\x34\x01\xDF\x04\x16\x93\xDE\xA1\xCB\x2A\xEF\x02\xDF\x40\xF2\xBA\x83\xA0\xC7\x1C\x4E\x39\x92\x2E\xF2\x22\xB3\x81\x63\xBB\x1C\xB1\x20\x00\x76\x04\x1E\x26\xBD\xC3\x86\x74\x2E\xFF\x83\x1C\xEC\x08\x82\xF7\xD1\x80\x6C\x67\xAC\x20\xBD\x93\x86\x74\x2D\x2B\x90\x35\x89\x98\x56\x07\x00\xEC\x0E\xFC\x85\xF4\x8E\x19\xD2\x3B\x79\x06\xD8\xA7\x93\xF1\x0C\x4A\x42\x7F\xE0\x12\x24\x33\x28\xB5\x33\x86\xF4\x4D\x5A\x81\x0B\x91\x19\x54\x50\x22\xC6\x21\xE7\x59\x53\x3B\x60\x88\x8E\x3C\x49\x7C\x1B\x97\x86\x49\xC0\x7B\xA4\x77\xBA\x10\x5D\x59\x02\x9C\x44\xC9\x28\xD3\x81\xFE\x81\xC0\xCF\x80\x2F\xA6\xEE\x48\x0D\xAC\x00\x5E\x41\x6A\x56\x35\x57\xFF\x7C\x9B\xF5\x75\xAD\xE6\x23\x7B\xA7\x20\x55\x32\x96\x55\xFF\x3E\x88\xF5\x8B\x3E\xC3\x58\x5F\x43\x6B\x04\x92\x2C\x31\x0E\xA9\xB5\x35\x0E\xD8\x16\xB1\x55\x5E\xB9\x01\x38\x13\x58\x99\xBA\x23\x1E\x94\x25\x80\xC7\x01\x77\x03\x7B\xA4\xEE\x48\x2F\x58\x08\x4C\x01\x9E\x42\x6A\x52\x3D\x83\x04\xEF\x3A\xE3\xDF\xED\x07\x8C\x07\x76\x43\x6A\x72\xED\x09\x7C\x1C\x18\x6E\xFC\xBB\x9A\x4C\x07\x8E\x46\x8E\x30\x06\x39\xE7\x60\xE4\xCD\x94\x7A\x8A\xD7\x9D\xCC\x03\x6E\x05\x4E\x01\x76\x22\x5B\x0F\xD7\x3A\xA4\x4F\xA7\x02\xB7\x91\x1F\x7B\x4E\xB4\x30\x46\xE0\xC7\x19\x64\x7B\x95\x79\x26\xB2\x8A\xBA\x2F\xF9\x3A\x1B\xDB\x0F\xF8\x28\x70\x11\x32\x3B\x48\x6D\xC7\x8D\x49\x2B\x72\xE4\x33\xC8\x19\xF5\xC0\x15\xA4\x77\xA0\xCE\xE4\x79\xE0\xBB\x48\x35\xCA\xA2\xB0\x13\x92\x5C\xF1\x02\xE9\xED\xDB\x99\x5C\x4E\xB6\x66\x34\x41\x17\x0C\x04\x7E\x4D\x7A\xA7\x69\x2F\xCB\x80\x9B\x90\x6F\xC9\xA2\x33\x01\xB8\x99\xEC\x1D\xBB\xBC\x03\x18\x60\xA8\x77\xA0\xC0\x10\xE0\xFF\x48\xEF\x2C\x6D\xD2\x0C\x9C\xC5\xFA\xDB\x12\xCA\xC4\x30\xE0\x1C\x64\xA5\x3C\xF5\x38\xB4\xC9\x23\x48\x25\x95\x20\x83\x0C\x07\xA6\x92\xDE\x49\x2A\x48\xB1\xF3\xE3\xC8\xD7\x77\xAD\x15\x0D\xC0\x09\x64\x27\x5D\x75\x0A\x51\xC2\x27\x73\x8C\x02\x9E\x26\xBD\x73\xCC\x44\x8E\xBD\xC5\xF7\x56\xE7\x4C\x04\xFE\x4C\xFA\x71\x7A\x0A\xA9\xB0\x12\x64\x80\xCD\x80\x59\xA4\x75\x88\x59\x48\x95\xC5\x08\xDC\xEE\xA9\x03\x3E\x4B\xFA\x05\xAF\x67\x91\x84\x96\x20\x21\x43\x49\x3B\x35\x5B\x88\x1C\x43\x8C\xA3\x6D\xBD\xA7\x01\xD9\xE2\x99\x47\xBA\xF1\x9B\x01\x6C\x6A\xAD\x68\xD0\x39\x43\x48\xF7\xCD\xBB\x16\xB9\x2A\x25\x06\xBF\x76\x46\x02\xD7\x22\x19\x66\x29\xC6\x72\x0A\xB1\xB0\xE5\xCE\x40\xE0\x51\xD2\x0C\xF8\x2C\xCA\xB1\x1D\xE4\xCD\x04\xD2\x4D\xAB\x1F\x26\xB6\x98\xDC\xA8\x27\xCD\x3E\x6F\xDB\xD9\xD3\x26\x7B\x15\x4B\x4B\x13\x72\x46\xBB\x15\xFF\xF1\xBD\x9D\x58\xC3\x70\xE1\x47\xF8\x0F\x6E\x33\x72\x87\x6F\xE0\xC3\x3E\x48\x21\x3B\xEF\x71\xBE\xCC\x43\xB9\x32\x73\x06\xFE\x83\x7A\x3D\xF1\x8D\x94\x82\x21\x48\xF6\x9A\xF7\x78\x9F\xEA\xA0\x5B\x29\x39\x18\xDF\x83\x09\xCB\x81\x2F\xB8\x68\x16\x74\xC5\x97\xF0\x2D\x36\xD8\x0A\x7C\xCA\x45\xB3\x12\xB1\x0D\xBE\xDB\x0D\xAF\x01\x7B\xBB\x68\x16\xF4\x84\x3D\x80\xB9\xF8\x8D\xFF\x02\xE4\x0C\x79\xA0\xC0\x40\x24\x73\xC6\x6B\xF0\x1E\x25\xB6\x87\xB2\xC8\x48\xE0\x8F\xF8\xF9\xC1\x34\x62\x65\x5A\x85\x1B\xF0\x1B\xB4\x38\xB1\x92\x6D",
				"\x9A\x80\x5F\xE1\xE7\x0F\xBF\xF4\x51\xAB\xB8\x4C\xC2\x6F\xB0\x2E\x22\xB6\x11\xF2\x40\x1D\xB2\x5A\xEC\xE5\x17\xB1\x0E\xD2\x47\xC6\xE3\x73\x23\xE0\x3A\xE4\xD8\x5B\x90\x2F\xCE\xC4\x27\x7B\xEB\x3D\xA2\x64\x6D\xAF\x69\x00\xFE\x84\x4F\xF0\x7E\xD5\x49\xA7\x40\x9F\xD3\x90\xB4\x56\x6B\x3F\x99\x86\x5C\x04\x10\xF4\x90\x8B\xB1\x1F\x94\xB5\xE4\xBB\xC4\x6C\x20\x9C\x84\x4F\x10\x5F\xE0\xA3\x4E\xFE\xD9\x1B\xFB\xFD\xDE\x75\xC0\x97\xBD\x14\x0A\xCC\x39\x03\xFB\xE9\x74\x2B\xB0\x97\x97\x42\x79\xA5\x01\x9F\x2D\xA3\xF3\xBC\x14\x0A\xDC\x38\x0B\x7B\xBF\x79\x86\x98\x4A\x77\xC9\xB7\xB1\x1F\x84\x8B\xDC\xB4\x09\xBC\xB9\x1C\x7B\xFF\x39\xDF\x4D\x9B\x9C\xB1\x03\xF6\x29\x73\xB7\x11\x5B\x45\x45\xA6\x0E\xF8\x4F\x6C\x7D\x68\x39\xB0\x9D\x97\x42\x79\xE2\x61\x6C\x0D\xFF\x28\x51\x39\xA3\x0C\x0C\xC0\x3E\x63\xEB\x41\x37\x6D\x72\xC2\x51\xD8\x1A\x7C\x2E\x91\x1E\x59\x26\x46\x22\xF7\x22\x59\xFA\xD4\x61\x6E\xDA\x64\x9C\x46\xE0\x65\xEC\x0C\xBD\x82\x58\x3D\x2C\x23\xBB\x63\x5B\x5C\x7E\x0E\x51\xDC\x01\x80\x7F\xC1\xF6\x49\x79\xB2\x9F\x2A\x41\xC6\xF8\x27\x6C\x7D\xAB\xF4\x19\x7C\x23\x81\xC5\xD8\x19\xF8\x17\x7E\xAA\x04\x19\xE5\x66\xEC\xFC\x6B\x11\x25\xFF\x34\xB3\xBC\x80\x6C\x0E\x52\xD5\x21\x28\x37\x83\xB1\xFD\x44\xBB\xD4\x4F\x95\x6C\x31\x06\xB9\xF4\xCB\xC2\xA8\xAD\xC8\xF5\x97\x41\x00\x92\xDD\xB7\x1A\x1B\x5F\x5B\x8A\xDC\x0C\x52\x3A\xAE\xC2\xEE\xA9\x78\x81\x9F\x1A\x41\x4E\xB8\x04\x3B\x7F\xFB\x91\xA3\x1E\x99\x60\x4B\xEC\x92\x36\x66\x11\xFB\xBD\xC1\x86\x0C\xC0\xAE\xEE\xF4\x72\x64\x46\x59\x1A\x7E\x88\x8D\x21\xD7\x12\xE5\x5F\x83\x8D\xF3\x31\xEC\x4E\x2E\x95\xE6\x5B\x78\x08\xB2\x7A\x67\x61\xC4\x9F\x3A\xEA\x11\xE4\x93\xEB\xB0\xF1\xBD\x05\x94\xA4\xFC\xF0\xD9\xD8\x18\x70\x21\x30\xC2\x51\x8F\x20\x9F\x6C\x8A\x04\x9B\x85\x0F\x7E\xCD\x51\x0F\xC0\x3F\xB1\xBF\x1F\xB2\xA4\xBF\xAD\x41\xDB\x5F\xA1\x9C\x6F\xE0\x7A\x60\x4F\x60\x7F\x60\x2C\xB0\x35\xB0\x55\xF5\xCF\x21\xC8\x4A\xFF\x62\xA4\x3C\xD1\x32\x24\xC5\x70\x6A\x55\x66\x20\x2B\xF6\x65\xE3\x6C\xE0\x4A\x83\x76\x5B\x90\xF2\x3B\x6B\x0C\xDA\xCE\x04\x56\x39\xCF\xB3\x90\xB3\xC4\x65\x61\x38\x72\xEB\xFD\xCD\xC0\x5B\xF4\xDD\x6E\xCB\x91\xC4\xFF\xB3\xAA\x6D\x96\x85\xFE\xD8\x2D\x68\x7D\xC6\x51\x0F\x77\x7E\x87\x8D\xD1\x8E\xF4\x54\x22\x21\x5B\x03\x93\xB1\xD9\x3F\x5F\x09\xDC\x09\x4C\x74\xD3\x26\x2D\xC7\x60\xE3\x8B\xF7\x7A\x2A\xE1\xC9\x56\xD8\x94\xCA\xF9\x0B\xC5\x3F\xE3\xBB\x23\x52\x1F\xDB\x2A\x19\xA1\xA3\x4C\xA3\xF8\x57\xA8\xD6\x01\x4F\xA3\x6F\xBB\x35\x88\xAF\x17\x8E\x0B\xB1\x71\xB6\x43\x3D\x95\x70\xA6\x11\xF8\x3E\xBE\x77\x42\xB5\xC9\x5A\x64\xC5\xB6\xC8\x53\xEB\x23\xB0\xB1\xDD\x77\x3C\x95\xF0\xA0\x1E\xB9\x6F\xC8\xE2\x4D\x51\x54\x3E\x08\x4C\xC7\x3F\x70\x3B\xCA\x02\xA4\x7C\x6B\x11\x67\x39\x75\xD8\xD8\xB8\x99\x82\xD9\xEB\x00\x6C\x9C\xEB\x38\x4F\x25\x9C\xA8\x43\x02\x66\x29\xE9\x83\xB7\xBD\xDC\x48\x31\x0B\xBA\x7D\x1E\x1B\x7B\x15\xEA\x13\xE4\xA7\xD8\x3C\xE5\x8A\xB6\xF2\x5C\x07\x5C\x4D\xFA\x60\xDD\x98\x3C\x44\xF1\x4E\x78\x35\x20\xDB\x3F\xDA\xB6\xBA\xCA\x51\x07\x53\xFA\x01\x6F\xA2\x6F\xA0\xB3\x3C\x95\x70\x20\xEB\xC1\xDB\x26\xD3\x80\xD1\x46\x36\x48\xC5\x39\xE8\xDB\xE9\x0D\xE4\xD3\x31\xF7\x1C\x84\xBE\x71\x96\x53\xAC\xC5\x95\x3A\xE0\x27\xA4\x0F\xCE\x9E\xCA\xCB\x14\x2B\xEB\x6D\x18\x36\x5B\x73\x9F\xF0\x54\xC2\x0A\x0B\xC7\xBC\xD1\x55\x03\x7B\xAE\x24\x7D\x50\xF6\x56\x7E\x4F\xB1\x3E\x61\x2C\xCA\xD1\x16\x62\x1A\x3D\x07\x7D\xC3\x14\x69\x81\xC0\xBA\x22\xA7\xA5\xFC\xD8\xC0\x1E\xA9\x38\x00\x7D\xFB\xBC\xE4\xAA\x81\x01\x3B\xA0\x6F\x94\xE7\x5D\x35\xB0\xA5\x11\x59\x8C\x4B\x1D\x88\xB5\xC8\x89\xEA\x56\x49\x43\x1D\x30\x1B\x7D\xFB\x8C\xB7\xEC\xB4\xF5\x47\xB6\x45\x92\xC5\xED\x06\x6D\xA6\xE2\x28\xE4\x00\x42\x9E\xB9\x0E\x49\xF1\xCC\x3B\x15\x6C\x7C\xEB\x60\x83\x36\xDD\x78\x10\xFD\x27\xDA\x87\x5C\x35\xB0\xE5\x0E\xD2\xBF\x41\x35\xE4\x16\x6D\xC3\x24\x62\x67\xF4\x6D\x93\xDB\xDC\xE8\xFE\xE8\xAF\xEC\x3D\xE3\xAA\x81\x3D\xAF\x90\x3E\xF8\x34\x64\x1D\xB0\xAF\xB2\x6D\x52\x31\x0B\x5D\xDB\xBC\x87\xE1\x62\x9F\xE5\x14\x7A\x37\x60\x13\xE5\x36\xFF\x4B\xB9\xBD\xD4\x6C\x91\xBA\x03\x4A\xD4\x21\x2B\xAE\x45\x48\x1F\xFC\x8D\x72\x7B\x83\x81\x5D\x94\xDB\xFC\x1B\x96\x01\x3C\xC1\xA0\xCD\x07\x0C\xDA\x4C\x49\x25\x75\x07\x14\xF9\x28\x70\x78\xEA\x4E\x28\x60\x71\x71\x99\x59\x9D\x36\xCB\x00\xD6\xDE\xEA\x99\x8F\x1C\x1D\x2C\x12",
				"\x6F\xA5\xEE\x80\x32\x93\x52\x77\x40\x81\xA9\x48\x79\x26\x4D\x22\x80\x91\x3C\xDC\xB5\xCA\x6D\xA6\xA6\x68\x0F\xA4\x43\x90\xEB\x72\xF2\xCC\x5A\xE0\x7F\x95\xDB\xCC\x5D\x00\x8F\x41\x6A\x3F\x6B\xF2\x88\x72\x7B\x59\x40\xFB\x9B\xBE\x82\x54\x3D\x99\x84\xAC\xD6\x6F\x02\x0C\x44\xB6\x79\x8E\x46\xB2\x8D\x56\x2A\xFF\x66\x7B\x1A\x81\xE3\x0D\xDB\xF7\xE2\x0F\xCA\xED\x6D\x05\x6C\xA6\xDC\xA6\x29\x9F\x46\x7F\xA5\xB3\x48\xDB\x47\x6D\x34\xA1\x77\x8F\xED\x54\x60\xD7\x1E\xFC\xE6\x18\x64\xDB\xC7\x6A\x45\x7A\x6A\x9F\x2C\x91\x2D\x76\x41\xDF\x2E\x07\xB9\x6A\x50\x23\xE7\xA2\xAB\xFC\x42\x0A\x72\xB2\xA3\x13\x8E\xA5\x76\xFB\xFC\x9C\xDE\x6F\x55\x4C\x42\x2A\x52\x5A\x04\x71\xDE\x0F\x3A\xD4\xA1\x5F\x7A\xF6\xEB\xAE\x1A\xD4\xC8\x4D\xE8\x2A\x7F\x9F\x6B\xEF\xFD\xB9\x86\xBE\xDB\xE6\x3A\xFA\xBE\x7D\x73\x72\x0D\xBF\xDB\x95\xE4\xEA\x6D\xB3\x11\xB4\x0B\x30\x5E\xEF\xDB\xFD\xDA\xD0\x2E\x53\x72\xA1\x6F\xF7\xDD\xA9\xA7\x6F\x41\x7C\x0D\xB5\xCF\x4C\x6E\xE8\xC3\xEF\x76\x27\x45\xB8\xF8\xFA\x62\x74\x6D\xF2\xA4\x6F\xF7\x6B\x63\x09\xBA\xCA\x1F\xED\xDB\xFD\x64\x1C\x87\x1C\x04\xEF\xCE\x1E\x6F\xA0\x57\x4E\x68\x34\xFA\xE3\x75\xB3\x52\xDF\x52\x72\x3C\xBA\x36\xD1\xDE\x9A\x32\x63\x04\xFA\x4F\xF4\xED\x5D\x35\x48\x4B\x13\x72\xC2\xE7\x2E\xE4\xA4\xD2\x9A\xAA\x34\x57\xFF\xDB\x89\xD5\x7F\xA3\xC9\xF5\xE8\x8E\x57\x11\x52\x5E\x3F\x84\xBE\x1F\x0F\x73\xD5\xA0\x8F\xEC\x85\xAE\xD2\xCB\x90\xB2\x3C\x81\x1D\x87\xA0\x3B\x66\x45\x48\x50\x69\x40\xFF\x0A\xDC\xDD\xB5\x3B\x69\xB1\xB2\x3B\x4E\xB9\xBD\xB9\x14\x2F\x81\x23\x6B\x4C\x57\x6E\xAF\x08\x95\x3A\xD6\x20\x5B\x7C\x9A\x8C\x55\x6E\xCF\x24\x80\xB7\x51\x6E\xAF\x45\xB9\xBD\x60\x43\xE6\xA1\xFB\x90\x2C\x4A\xF9\xD9\xB9\xCA\xED\x69\xBF\xDC\x4C\x02\x58\xBB\x62\x61\xB3\x72\x7B\x41\xE7\x44\x00\x6F\x48\x8B\x72\x7B\x63\x94\xDB\x33\x09\x60\xED\x5C\xD8\x16\xE5\xF6\x82\x0D\x19\x83\xA4\x41\x6A\x51\x84\x29\x34\xE8\xBF\x3C\xD4\x13\x5C\x2C\x02\x58\xBB\x93\x6F\x2B\xB7\x17\x6C\x88\xF6\xE2\x4A\x6E\xB6\x4C\xBA\x41\x7B\x31\xAE\x94\x01\xBC\x40\xB9\xBD\x60\x43\xB4\xF7\xD9\x73\x5F\x8D\xB1\x8A\xB6\xEF\xA9\x9F\xD4\xCA\xC3\x14\x7A\xBE\x72\x7B\xC1\xFB\xD9\x1C\xF8\x9C\x72\x9B\x11\xC0\x9D\x93\x8B\x37\xF0\x20\xE5\xF6\xE2\x0D\x6C\xCB\x65\xE8\x8F\xD9\xCB\xCA\xED\xA5\x42\xFB\xE5\xA1\x6D\x67\x93\x00\xD6\xCE\x12\x5A\xAA\xDC\x5E\xB0\x9E\x49\xC0\x49\x06\xED\x16\xE5\x0D\xBC\x4C\xB9\x3D\xED\xD8\x30\x61\x11\x25\x4C\x3F\xCB\x21\xA7\x60\x73\x71\x78\x2B\x39\x3B\xBC\xDE\x05\xC3\xD1\xB5\xCD\x22\xDF\xEE\xF7\x8D\xE5\xE8\x2A\x3D\xD0\xB7\xFB\x85\x67\x0B\xE0\x56\xF4\x03\xB7\x4D\x7E\xEF\xA7\x8A\x39\x9B\xA0\x6B\x1B\xED\x37\xBA\xC9\x7E\x9D\xE6\x7E\x22\xC0\x6A\xE5\xF6\xCA\xC6\x26\x48\x72\xCD\x3E\xC0\x61\xC8\x29\x26\xED\x31\x6A\xCF\x9D\x86\x6D\x7B\xB3\x4A\xB9\xBD\x5C\x4C\xA1\xB5\xA7\x65\x71\x90\xA1\xE7\x34\x02\x27\x20\x57\x84\xCC\xC1\xAE\xE2\xC6\xC6\x64\x35\xF9\x2F\x6A\xD7\x9E\x7E\xE8\xDA\x67\x8D\x6F\xF7\xFB\x46\x4C\xA1\xD3\x70\x34\xF0\x1A\xBE\x01\xDB\x51\x2C\x6A\x2A\xA7\x24\xF3\x53\x68\x0B\x62\x11\xCB\x97\x7A\x60\x32\x69\x03\xB7\x4D\x3E\x6D\xAC\xAB\x37\xA5\x5C\xC4\x7A\x07\x5D\xA5\x8B\xB2\xA2\x69\x45\x56\x82\x57\xBB\x96\x72\x16\x18\x83\xAE\x8D\x72\x71\x4E\xFA\x75\x74\x95\x56\x3F\x82\x55\x20\x8E\x26\x7D\xE0\x56\x90\xCB\xCD\x3E\x62\xAC\x6B\x0A\xC6\xA3\x6B\x27\xED\xF3\xC5\x26\x89\x1C\xDA\xF3\xFC\x22\x2D\x8A\x68\xD2\x08\x5C\x91\xBA\x13\x55\xEE\xA2\x78\xB7\x4C\x80\xBE\xEF\xA9\x7F\x03\x5B\x04\xB0\x76\xFA\x59\xDE\x6B\x0C\x5B\xF1\x59\xB2\x31\x3B\x59\x0C\xFC\x6B\xEA\x4E\x18\xA1\xED\x7B\xEA\x79\xFD\x16\x01\x9C\xF9\x04\xF0\x82\x70\x54\xEA\x0E\x20\xD3\xC2\x93\xD1\xAF\x5C\x91\x15\x32\x7F\xB2\x2E\x0F\x01\xAC\x5E\xC5\xA0\x20\xEC\x9D\xBA\x03\xC8\x14\xBE\x68\x77\x36\xB7\x47\xDB\xF7\x72\x11\xC0\xDA\xD3\x84\xB1\xCA\xED\x15\x85\xCD\x13\xFF\xFE\xA3\xC0\xB7\x13\xF7\xC1\x1A\xED\x4F\x94\x5C\x4C\xA1\xB5\x2B\x68\x8C\x55\x6E\xAF\x28\x54\x12\xFE\xF6\x4C\xA4\xF0\x79\x2E\x32\x8B\x6A\x60\xAC\x72\x7B\xEA\xDB\x48\x16\x01\xDC\xA2\xDC\xDE\x58\xE5\xF6\x8A\x42\xAA\x3D\xC5\x29\xC0\x81\xC8\x7E\x7F\xD1\xD9\x56\xB9\xBD\x66\xE5\xF6\x4C\x02\x58\xBB\x93\xE3\x89\x7C\xE8\xCE\xF8\x73\x82\xDF\x7C\x10\xC9\xB6\xCA\x45\x46\x51\x8D\x34\xA0\xFF\xF2\x68\x51\x6E\xCF\x84\x4D\xD1\x4F\x14\xD8\xD1\x55\x83\x7C\x70\x02\xBE\xC9\x1A\x37\x62\x7B\x8A\x29\x6B\x7C\x18\x7D\x1B",
				"\x0E\x75\xD5\xA0\x06\xDE\x45\x57\xF1\x63\x7C\xBB\x9F\x0B\x1A\x91\xED\x1B\xEB\xC0\x7D\x13\xD9\x73\x2E\x1B\xDA\x0F\x48\x93\xD2\x50\x56\x97\x66\xCF\x51\x6E\xAF\x27\x37\xCF\x97\x8D\xD5\xC0\x79\xC6\xBF\x71\x13\xB0\x13\xF0\x1B\xE3\xDF\xC9\x22\x3B\x2B\xB7\xA7\x1D\x13\x80\x5D\x00\x3F\xAB\xDC\xDE\x9E\xCA\xED\x15\x85\xBB\x81\xAB\x0D\xDA\x7D\x18\x98\x88\x24\x69\x94\xE1\x7B\xB7\x33\xB4\x7D\x6E\xA6\x72\x7B\xA6\x9C\x8D\xEE\xF4\x63\x21\x76\x0F\x9B\xBC\xA3\x75\x9C\x70\x15\xF2\xC6\xDD\xCD\xB5\xF7\xD9\xA4\x1E\xFD\xCF\xC0\xAF\xBA\x6A\x50\x23\x13\xD1\xFF\x16\xDB\xC9\x55\x83\xFC\xD1\x97\x03\xFD\x8B\x80\x7B\x80\xAF\x93\x3E\x31\x24\x4B\xEC\x8A\xBE\xFF\x1E\x68\xD1\x51\xAB\x3B\x6C\x2C\x2E\x78\xDE\x0F\x78\xDE\xA0\xDD\xA2\x70\x37\x70\x2F\xB2\xE0\x74\x24\x72\xBC\x6F\x1B\xE4\xCD\x3A\x0F\x49\xB0\x99\x5F\xFD\xFB\x0B\xC0\x1F\x80\xA7\x88\xAB\x5B\x3B\x63\x82\x41\x9B\xCF\x19\xB4\x69\x8A\xF6\xB9\xE0\xDB\x7C\xBB\x1F\x94\x98\xBB\xD0\xF5\xDD\x16\xD7\xDE\x2B\x71\x3B\xBA\x46\x58\x40\x24\x74\x04\xF6\x34\xA0\x5F\x16\xEA\x16\xAB\xCE\x5A\x2E\x0C\x4D\x51\x6E\x6F\x53\xB2\x71\x02\x27\x28\x36\x1F\x43\xBF\x0E\xDB\x13\xCA\xED\xFD\x0D\xCB\x00\xB6\xE8\xF4\xDF\x1B\xB4\x19\x04\xED\x39\xC4\xA0\x4D\xED\x97\x99\x0B\x0D\xC0\x7B\xE8\x4E\x45\xB4\xF7\x97\x83\xA0\x23\xCF\xA3\xEB\xB3\x8B\xC9\xF1\xA7\xDF\xEF\xD0\x35\x46\x85\xD8\x4E\x0A\xEC\xD8\x0D\x7D\x7F\xBD\xC7\xB2\xC3\xD6\xC9\x11\x16\x85\xBE\x8F\x33\x68\x33\x08\xC0\xC6\xB7\x72\x5D\xEC\x7E\x7B\xF4\x9F\x68\x2F\xB8\x6A\x10\x94\x85\x3A\x24\x5F\x59\xDB\x5F\xB3\x50\x78\xB0\x26\x66\xA3\x6F\x94\xFD\x5C\x35\x08\xCA\xC0\x27\xC9\xE1\xCB\xC6\x23\xBF\xF8\x01\x83\x36\x4F\x33\x68\x33\x28\x37\x93\x0C\xDA\xCC\xF5\xF4\xB9\x8D\x03\xD0\x7F\xB2\x2D\x47\xEE\xAD\x09\xDE\x4F\x67\xB7\x13\xB6\x56\xFF\x7E\x7B\xF5\x7F\x2B\xD3\xA1\xFC\x9E\x32\x0C\xFD\x4B\xF9\x0A\x33\x53\xAC\x07\xFE\x8A\xBE\x71\xCE\xF6\x54\x22\x07\xF4\xF4\x30\xC3\x6B\xD5\x7F\x1B\xAC\xE7\x5C\xF4\xFD\xF3\x75\x0A\x74\x82\xEE\x6A\x6C\x0C\xD4\xDF\x53\x89\x8C\xD2\xD7\xE3\x84\x93\x29\x90\x83\xD5\x40\x7F\xE4\xCE\x22\x6D\xFF\xFC\xB1\xA7\x12\xD6\x4C\x40\xDF\x40\x15\x64\x4A\x58\x76\x6A\x39\x0B\x3C\x39\x41\x7F\xB3\xC6\x89\xD8\xF8\xE6\x3E\x9E\x4A\x58\x53\x8F\xCD\x53\x2E\x45\x65\xC6\x2C\xA1\x71\x3B\x61\x99\xA7\xD3\x75\xC0\xD3\xE8\xFB\xE5\x2B\xD5\xB6\x0B\xC5\xF7\xB0\x79\xD2\xFD\x83\xA7\x12\x19\x42\xAB\xA8\x5D\x0B\xD0\xE4\xDB\xF5\xCC\x70\x24\x36\x3E\xF9\x2D\x4F\x25\xBC\xF8\x00\x52\xC9\x5F\xDB\x58\xD3\x29\xE0\xD3\xAE\x07\x68\x56\x4D\x3C\xDE\xB9\xEF\x59\xA0\x0E\x98\x81\xBE\x3F\xB6\x02\x5B\x38\xEA\xE1\xCA\xFD\xD8\x3C\xF1\xCA\x58\xF6\xF4\x0E\xF4\xEC\x77\x87\x73\xDF\xB3\xC0\xF1\xD8\xF8\xA2\x69\xEE\x73\x6A\x3E\x83\x8D\xD1\x5E\xA0\x7C\x2B\xD2\x9A\x35\xA1\x8B\x7A\x3D\xE8\xC6\x68\x04\x5E\xC6\xC6\x17\x0F\x77\xD4\xC3\x9D\x7E\xD8\xE4\x9B\x56\x90\xC2\x6C\x65\x62\x05\x7A\xB6\x5B\xE1\xDC\xF7\xD4\x9C\x87\x8D\x0F\xCE\x25\xC7\x47\x07\x7B\xCA\xD7\xB0\x31\xDE\x42\x60\xA4\xA3\x1E\xA9\x59\x89\x9E\xED\x56\x3A\xF7\x3D\x25\xA3\xD0\x2F\x19\xDB\x26\x67\x3A\xEA\x91\x8C\xC1\x48\xB0\x59\x18\xF0\x5A\x47\x3D\x52\xA3\xB9\x2D\xF7\xAA\x73\xDF\x53\xF2\x0B\x6C\x7C\x6F\x3E\x30\xC8\x51\x8F\xA4\x7C\x1F\x1B\x23\xAE\xC5\xA6\x24\x68\x16\xF9\x2D\x7A\x76\xFB\xAD\x73\xDF\x53\x71\x00\xB0\x0E\x1B\xDF\xBB\xC8\x51\x8F\xE4\x6C\x81\xEE\x37\x5C\x7B\x79\x81\x72\xEC\x6B\x9E\x8C\x9E\xCD\x4E\xF2\xED\x7A\x12\x06\x62\xB7\x70\xB5\x0C\x18\xED\xA7\x4A\x36\xB8\x12\x1B\x63\x56\x80\x8B\x1D\xF5\x48\xC5\x20\xE4\x92\xEF\x5A\x6D\xF5\x16\xE5\x98\xFA\x59\xCD\xFA\x2A\xC0\x0F\x1D\xF5\xC8\x0C\x9B\xA1\x5F\xF4\xAE\x4D\x5A\x91\xF2\xA0\x45\xE7\x14\x6A\xB7\xD5\x29\xEE\xBD\xF6\x67\x3F\x6C\x92\x88\x2A\x88\x0F\x8F\xF2\x53\x25\x5B\xFC\x00\xBB\xA7\xE2\x2B\xC0\xDF\xF9\xA9\x92\x8C\xDB\xE8\xBB\x8D\xCA\x70\xDB\xC5\x50\xA0\x19\x3B\x3F\xBB\xC4\x4F\x95\xEC\x31\x02\xBB\x25\xFD\x0A\x72\xDB\x5E\xD1\x69\x04\xEE\xA4\xF7\xB6\xB9\x93\x72\x1C\xEE\xBF\x05\x3B\xFF\x5A\x44\x14\x96\xE0\x1B\xD8\x19\xB8\x82\x4D\xA9\x94\xAC\x51\x87\x5C\x5F\xB9\x98\xEE\xED\xB1\xB8\xFA\x6F\xCB\x90\x3F\x7E\x3A\xB6\xBE\x55\xB6\xE4\xA1\x4E\x69\x04\x5E\xC2\xCE\xC8\x2B\x28\xCF\x95\x2C\xC3\x81\x73\x80\xC7\x78\x7F\x89\x98\xE5\xD5\xFF\x76\x0E\xE5\x79\x63\xEC\x8B\x6E\xB2\x4B\x47\x29\x63\xFA\xEE\x46\x39\x02\xDB\x27\x65\x0B\xE5\xCA\xD2\x6A\x63",
				"\x38\xE5\x09\xD8\xF6\x8C\x42\xFF\x76\xCC\x8E\x72\xA8\x9B\x36\x39\xE1\x21\x6C\x0D\xFE\x18\xE5\xD8\x1F\x2E\x3B\x03\x91\xBB\x88\x2C\x7D\xE9\x3E\x37\x6D\x72\xC4\xF6\xD8\x54\x06\x6C\x2F\x77\x50\x8E\x6F\xBF\xB2\x52\x87\xED\xA2\x55\x05\x49\xDA\x18\xEF\xA5\x50\xDE\x38\x1F\x5B\xE3\x57\x80\x4B\xDD\xB4\x09\xBC\xB9\x02\x7B\xFF\x39\xD7\x4D\x9B\x1C\xD2\x80\x54\xD8\xB0\x1E\x84\x6F\x7A\x29\x14\xB8\x71\x36\xF6\x7E\x33\x83\x58\xB8\xEA\x96\xBD\x90\x4C\x2A\xCB\x81\x58\x87\x6C\x31\x04\xC5\xE0\x2B\xD8\x07\x6F\x2B\xB0\x87\x97\x42\x79\xE7\x02\xEC\x07\x64\x2D\xE5\x48\xE2\x2F\x3A\x93\xB0\x3B\x61\xD4\x5E\xBE\xEB\xA5\x50\x11\x68\xC0\x7E\x25\xB1\xED\x4D\x1C\x9B\xF1\xF9\xE5\x74\xE4\x41\x6C\xED\x27\x8F\x53\x82\x4A\x1B\xDA\x6C\x4B\xCF\x32\x8B\x34\xE4\xDF\x9C\x74\x0A\xF4\xF0\x58\xF0\xAC\x20\xA9\xBE\x63\x7D\x54\x2A\x1E\x5F\xC4\x67\x90\x2A\xC8\x71\xB3\xD8\x62\xCA\x3E\xF5\xF8\xAC\x36\xB7\xC9\xE7\x7D\xD4\x2A\x2E\xFF\x81\xDF\x60\xFD\x1A\x49\x04\x08\xB2\x49\x13\x70\x2B\x7E\xFE\xF0\x33\x1F\xB5\x8A\xCD\x00\xE4\x0A\x15\xAF\x41\xFB\x23\xE5\x4C\xBB\xCC\x3A\xA3\xF0\x59\x17\x69\x93\xA9\x44\xE6\x9E\x1A\x5B\x01\xEF\xE0\x37\x78\xAF\x23\xC9\xF0\x41\x36\xD8\x0B\xDB\x33\xBD\x1D\xE5\x6D\xE4\x26\x91\x40\x91\x89\xD8\xEF\x0F\xB7\x97\x15\x94\xE3\x28\x62\xD6\xF9\x32\xB6\xA7\x8A\x3A\xCA\x6A\xE0\x40\x0F\xC5\xCA\xC8\x69\xF8\x0D\x64\x9B\xDC\x4C\x39\x2A\x7B\x64\x8D\xA1\xD8\xE7\x35\x77\x26\x5F\xF2\x50\xAE\xCC\x5C\x8E\xFF\xA0\xB6\x50\x9E\x72\xB5\x59\x60\x5F\xEC\x6E\xF0\xE8\x4A\x4A\x55\x1A\x36\x15\x75\xC0\xED\xF8\x0F\x6E\x2B\x52\xED\x32\x16\x36\xEC\x18\x00\x5C\x86\x5D\x01\xBA\xAE\xE4\x57\xC4\x36\xA2\x1B\x03\x80\x47\xF0\x1F\xE4\x0A\x52\x89\x61\x7F\x7B\x15\x4B\xC7\x81\xD8\x56\x66\xE9\x4A\x1E\x22\x1E\xCC\xEE\x0C\xC6\x77\x5B\xA1\xBD\xAC\x03\x7E\x8E\x94\xC6\x0D\x6A\x63\x14\x72\xDD\x89\x47\x3E\x73\x67\xF2\x38\xE5\xA8\x8B\x9D\x49\x86\xE2\xBB\x47\xDC\x51\x16\x21\x29\x7D\xF1\xF4\xEE\x3D\xFD\x91\x3C\x74\xCB\xAA\xA4\xDD\xC9\x0C\xCA\x59\x72\x28\x53\x8C\x04\x9E\x25\x9D\x13\x54\x80\x17\x81\x63\x89\x6F\xA8\x9E\x50\x0F\x1C\x87\xDD\x35\x27\x3D\x95\x67\x89\x84\x9D\xCC\x30\x1C\x78\x92\xB4\x0E\xD1\xE6\x14\x11\xC8\x1B\x67\x22\x3E\x05\x1B\xBA\x93\xE9\x44\xF0\x66\x8E\x61\xC0\x13\xA4\x77\x8E\x36\x07\xF9\x1C\x72\x2C\xB2\xEC\xF4\x07\xFE\x11\x78\x9A\xF4\xE3\x52\x41\x52\x65\x87\x9A\x6A\x1C\xF4\x99\xC1\xC0\xC3\xA4\x77\x92\x36\x79\x95\x72\xD5\x62\x6E\xCF\x70\xA4\x68\xFF\x6B\xA4\x1F\x87\x36\x79\x88\x58\xB0\xCA\x3C\x4D\xC8\x9E\x5E\x6A\x67\x69\x2F\x2B\x91\xAB\x4C\x26\x52\xFC\xE9\xF5\x5E\xC0\x75\x48\xF5\xC6\xD4\x76\x6F\x2F\x77\x22\xDB\x8F\x41\x0E\xA8\xC3\xF6\x3A\xC9\x5A\xE4\x65\x24\x21\x64\x67\x33\xED\xFD\xD9\x15\xB9\xE4\x2B\x45\xF6\x54\x4F\xE4\x62\x8A\xFF\xE0\x2C\x24\xA7\xE2\x7B\x00\xA2\xB7\x32\x0B\x71\xFC\xFD\xC8\x57\xC9\x96\x06\x24\xB5\xF4\x52\x24\xB1\x25\xB5\x1D\x37\x26\xAB\x91\x8B\xD0\x83\x1C\x73\x10\xBE\x47\x11\xFB\x2A\x0B\x91\xC2\xF3\xA7\x23\x6F\xE7\x7A\x0B\x63\xF4\x91\x7A\x60\x17\xE0\x0C\xE0\x2E\x64\xFF\x3B\xB5\xBD\xBA\x93\xB7\x29\xC1\xA9\xA2\xB2\x4C\x2B\xB6\x46\xAA\x6D\xE4\xE9\x92\xB3\x77\x91\x4C\xB3\xA7\x81\x99\xC8\x16\xD5\x6C\x24\x4F\xD8\x92\x06\x60\x07\x24\x60\x77\x45\x4A\xA9\x7E\x9C\x7C\xAD\xDC\x3E\x09\x1C\x03\xBC\x91\xBA\x23\xD6\x94\x25\x80\x41\x16\x30\x7E\x42\xBE\x6F\xA4\x5F\x05\xCC\x45\x4E\x47\x35\x57\xE5\x6D\x60\x41\x3B\x59\x8C\x04\xF9\x1A\xE4\xF6\x78\x80\x21\x48\x60\x36\x20\x81\x38\xA2\x9D\x8C\x06\xC6\x75\x90\x3C\x67\x96\x5D\x0B\x9C\x85\xD8\x2A\x28\x20\x5F\xC0\xAF\xDA\x65\x88\x9F\xBC\x4B\x14\xA0\x2B\x0D\xDB\x20\xB7\x15\xA6\x76\xBA\x10\x1D\xF9\x13\x71\xE1\x58\xE9\x68\x40\x6E\x80\xC8\xF2\x2A\x75\x48\xD7\xD2\x8A\xD4\xF4\xCE\xD3\x0A\x7E\xA0\xCC\x6E\xC0\x34\xD2\x3B\x63\x48\xEF\x64\x06\xF0\x91\x4E\xC6\x33\x28\x21\x0D\xC8\xD1\xB6\xA5\xA4\x77\xCC\x90\xAE\x65\x39\x72\x84\x33\xDE\xBA\xC1\x06\x6C\x07\x3C\x48\x7A\x27\x0D\xE9\x5C\xEE\x47\xAE\xDC\x09\x82\x2E\x99\x08\x3C\x47\x7A\x87\x0D\x11\x79\x09\x38\xAC\xCB\x11\x0B\x82\x0E\x34\x22\xB7\xB1\xA7\xAC\x18\x51\x76\x59\x88\xEC\xE9\xC6\xA5\xDA\x41\x9F\xD9\x14\x59\xAD\x8E\xBD\x63\x3F\x59\x8A\x94\x0F\x2E\xE3\x31\xCC\xC0\x88\x91\x88\x53\x65\xED\x98\x5C\x91\x64\x19\x30\x19\x18\xD3\xC3\x31\x09\x82\x5E\x33\x06\x39\x85\xB3\x80\xF4\x0E\x5F\x14\x99\x8F\x9C\xCA\x1A\xDD\x8B\x71\x08",
				"\x82\x9A\x18\x84\x5C\xF5\xF2\x22\xE9\x03\x20\xAF\x32\x17\xD9\xBE\x8B\x2A\x19\x41\x32\xFA\x01\x47\x00\xF7\x92\xE6\x46\x81\xBC\x49\x2B\x70\x0F\x70\x38\xB1\x97\x1B\x64\x8C\x2D\x81\xEF\x20\x6F\x96\xD4\x81\x92\x35\x99\x03\x7C\x0B\xD8\xA2\xCF\xD6\x0D\x02\x47\x3E\x8C\xAC\x5E\x97\x39\x98\xDF\x40\x16\xA5\x26\x50\xAE\xA3\xAB\x41\x81\xA8\x07\x3E\x01\x5C\x45\xBA\xBB\x7F\x3C\xE5\x45\xE0\xDF\x91\xA0\xCD\x52\x55\x91\x20\x50\x61\x5B\xE0\x9F\x91\x6F\xE6\x25\xA4\x0F\xB8\x5A\x65\x31\xF0\xDF\x48\xB9\x9D\x71\x8A\x76\x0A\x7A\x40\x4C\x6B\xD2\xD2\x0F\x29\x5D\x33\x01\x29\x5B\x33\x01\xD8\x2A\x69\x8F\xBA\xE7\x75\xA4\x38\xFA\x14\xE4\x62\xB0\xE7\x80\xB5\x49\x7B\x54\x62\x22\x80\xB3\xC7\x48\xA4\x16\xD5\x2E\xAC\xAF\x4B\xB5\x1D\xFE\x59\x49\x0B\x91\x85\xA7\xB6\x7A\x5C\xCF\x01\xCF\x20\xFB\xDF\x41\x46\x88\x00\xCE\x0F\x43\x91\x29\xEA\xD8\xAA\x6C\x8E\x04\x7B\xFB\xFA\x56\x4D\xD5\x7F\x57\x8F\xE4\x0F\x0F\xAE\xFE\x7F\x97\x22\xDB\x37\xEB\x90\x29\xEF\x2A\x24\x10\xE7\x57\xFF\x9C\x07\xBC\x85\xDC\x24\xD1\x5C\x95\x25\xE6\x1A\x05\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x10\x04\x41\x90\x7B\xFE\x1F\x25\x9C\xCB\x0D\x81\x4D\x43\xA2\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x57\x61\x72\x6E\x69\x6E\x67\x4E\x10\x00\x00\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\xF0\x00\x00\x00\xF0\x08\x06\x00\x00\x00\x3E\x55\xE9\x92\x00\x00\x00\x06\x62\x4B\x47\x44\x00\xFF\x00\xFF\x00\xFF\xA0\xBD\xA7\x93\x00\x00\x10\x03\x49\x44\x41\x54\x78\x9C\xED\xDD\x79\x90\x5D\x45\x15\xC7\xF1\xEF\x64\x60\x30\x09\x44\x03\x08\x84\x40\x58\x54\x16\x71\x05\x54\x10\x95\x45\x01\xA3\x28\x18\x8C\xE0\x96\x0A\x05\xEE\x08\x8A\x5A\x50\x28\x88\x22\x11\x15\x45\x10\x41\x50\x0A\x14\x64\x11\x0D\x41\x51\x70\x03\x14\x37\x16\x23\x2E\x41\x84\x10\x34\x2E\x09\x0A\x89\x04\x98\xEC\x13\xFF\xE8\x19\x8D\x43\x26\x33\xEF\xBD\xFE\x9D\xBB\xFD\x3E\x55\x5D\x54\xA5\x86\xFB\xCE\xE9\xDB\x7D\xEF\x7B\x77\x39\x0D\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\xB5\xD0\x55\x74\x00\x96\x55\x37\xB0\x19\x30\x1E\xD8\xB4\xFF\xBF\xAB\x80\xC5\xFD\x6D\x51\x7F\xB3\x9A\xF0\x04\xAE\xB6\xAD\x81\x03\x80\x3D\xFB\xDB\xF3\x81\x31\xC3\xFC\x3F\x8B\x80\x3B\xFB\xDB\x1D\xC0\x4D\xC0\x12\x61\x8C\x66\xB6\x96\xF1\xC0\x34\xE0\x3B\xC0\x4A\x60\x4D\x87\x6D\x69\xFF\xB6\xA6\x01\x63\x03\xF3\x30\x6B\x94\xED\x80\x0B\x81\xE5\x74\x3E\x69\x87\x6A\x8B\x80\x53\x80\x71\x41\x39\x99\xD5\xDE\x44\xE0\x7C\xB4\x13\x77\x70\x7B\x18\xF8\x08\xB0\x71\x40\x7E\x66\xB5\x35\x95\x34\x99\xA2\x26\xEE\xE0\xF6\x00\xB0\x9F\x3A\x49\xB3\xBA\xD9\x02\xB8\x96\xE2\x26\xEE\xDA\xAD\x8F\xF4\xD5\x7D\xB8\x8B\x63\x66\x06\xEC\x0E\x2C\xA0\xF8\x89\x3B\xB8\xDD\x01\x6C\x29\xCC\xDB\xAC\xF2\x0E\x00\x1E\xA1\xF8\xC9\x3A\x54\x9B\x07\xEC\x24\xCB\xDE\xAC\xC2\x8E\x20\xF6\x42\x55\xBB\xED\x41\xD2\xB7\x04\x33\xEB\xB7\x3F\xB0\x82\xE2\x27\xE7\x48\xDB\x02\xD2\x6D\x2D\xB3\xC6\xDB\x85\x74\xFF\xB5\xE8\x49\xD9\x6A\x9B\x03\x3C\x45\xD0\x1F\x66\x95\xB1\x19\x70\x3F\xC5\x4F\xC6\x76\xDB\x8D\xC0\xA8\xEC\xBD\x62\x56\x11\x97\x53\xFC\x24\xEC\xB4\x1D\x97\xBD\x57\xCC\x2A\x60\x32\xC5\x4F\xBE\x1C\xED\x71\x60\xC7\xCC\x7D\x63\x56\x6A\x63\x49\xB7\x64\x8A\x9E\x7C\xB9\xDA\x0D\x79\xBB\xC7\xAC\xDC\x3E\x4B\xF1\x93\x2E\x77\x7B\x63\xD6\x1E\x32\x2B\xA9\xA7\x53\x8D\xFB\xBD\xAD\xB6\xBF\xE1\xD7\x11\xC3\x75\x17\x1D\x40\x03\x5D\x4E\xBA\x75\x54\x37\xE3\x48\xD5\x3F\x6E\x29\x38\x0E\x33\x99\x57\x53\xFC\x99\x52\xD9\x7A\x81\xED\x73\x75\x96\x0D\xCF\x67\xE0\x38\x3D\xC0\x2C\x60\xF3\x80\xCF\x5A\x06\xCC\x06\x7E\x4B\xBA\x58\xB6\x8C\x74\xCF\x59\x7D\xCF\x76\x43\xD2\xFB\xCB\xD7\x88\x3F\xC7\x2C\xDC\x07\xD0\x9F\x01\x6F\x20\x9D\xE5\x7B\xD6\xF1\xF9\xE3\x48\x65\x73\x7E\x1B\x10\xC7\x7E\xED\x77\x93\x59\xF9\x6C\x09\xFC\x1B\xDD\x84\xF9\x3B\x70\xF0\x08\x63\xE9\x02\xDE\x43\xFA\xBA\xAB\x8A\xE7\x2E\xFC\xED\xCE\x6A\xE4\x2B\xE8\x26\xCB\x3D\xC0\xB6\x6D\xC4\xB4\x0F\xDA\x83\xCA\x3B\xDB\x88\xC9\xAC\x74\xF6\x00\x56\xA3\x99\x24\x0F\x01",
				"\x3B\x74\x10\xDB\x41\xC2\xD8\xFE\x45\xAA\xA0\x69\x56\x59\x5D\xC0\xAD\xE8\xCE\x72\xD3\x32\xC4\x78\xAE\x30\xBE\xCF\x67\x88\xCF\xAC\x30\x6F\x42\x37\x39\x7E\x4E\x9E\xC2\xFC\x9B\xA0\x2B\xE1\xB3\x12\x78\x56\x86\x18\xCD\xC2\x8D\x06\xFE\x8C\x66\x62\xAC\x06\x5E\x90\x31\xD6\xB7\x89\xE2\x5C\x03\xFC\x28\x63\x9C\x66\x61\x3E\x8E\x6E\x52\x7C\x39\x73\xAC\xA3\x80\xDB\x85\xF1\xBE\x36\x73\xBC\x66\x52\xDB\x92\x5E\xB3\x53\x4C\x86\x25\xC0\x56\x82\x98\x5F\x4C\x2A\x21\xAB\x88\x79\x2E\xB0\x91\x20\x66\x33\x89\x6B\xD0\x9D\xCD\x4E\x10\xC6\x7D\xA5\x30\xEE\x13\x85\x71\x9B\x65\xF3\x12\x74\x67\xB2\xFB\xD0\x9E\xC9\xB6\x01\x1E\x13\xC5\xBE\x04\x98\x20\x8C\xDD\xAC\x63\xDD\xA4\xA7\x90\x54\x67\xB1\x57\x05\xE4\xF0\x51\x61\xFC\x97\x04\xC4\x6F\xD6\xB6\x77\xA1\x1B\xFC\x3F\x08\xCA\x61\x34\x69\x4D\x24\x45\x0E\x7D\xC0\x0B\x83\xF2\x30\x6B\xC9\x78\xD2\xD3\x47\x8A\x81\xBF\x02\xD8\x39\x2E\x15\xDE\x20\xCA\x63\x0D\xF0\x4B\xBC\xB0\xBC\x95\xD0\x39\xE8\x06\xFD\x59\x81\x79\x0C\xB8\xA5\xCD\x58\x47\xD2\xDE\x12\x97\x86\xD9\xF0\x76\x45\xB7\xB2\xC2\x83\x14\x53\x40\xFD\x79\xA4\x0A\x1B\x8A\x9C\x16\xE0\x45\xC4\xAD\x44\x6E\x40\x77\xB6\x3A\x26\x30\x8F\xC1\xBE\xB4\x9E\xB8\x3A\x6D\x67\x04\xE6\x61\x36\xA4\x43\xD1\x0D\xF2\xD9\x14\xFB\x5E\xED\xA6\xA4\x37\x9E\x14\xB9\x2D\x07\x9E\x11\x97\x8A\xD9\x13\xF5\x00\x7F\x42\x37\x81\x5F\x16\x97\xCA\x90\xDE\x87\x2E\xBF\x6F\x05\xE6\x61\xF6\x04\x27\xA2\x1B\xDC\x57\x04\xE6\xB1\x3E\x1B\x00\xBF\x47\x97\xE7\x41\x71\xA9\x98\xFD\xCF\x96\xE8\x16\xE3\xEE\xA5\x5C\xCB\x77\xBE\x02\xDD\x04\x9E\x43\x3A\x48\x98\x85\xBA\x04\xDD\xA0\x3E\x35\x30\x8F\x91\xFA\x36\xBA\x7C\xDF\x13\x98\x87\x99\xB4\x4C\xCE\x7C\x60\x4C\x5C\x2A\x23\xF6\x34\x52\x79\x5A\x45\xCE\x8B\x88\x29\xB7\x6B\x26\x2F\x93\x33\x35\x2E\x95\x96\x7D\x1A\x5D\xDE\x5F\x08\xCC\xC3\x1A\xEC\xAD\xE8\x06\xF1\xCF\x28\xF7\x63\x86\x9B\x00\xFF\x40\x93\xFB\x2A\xE0\x39\x71\xA9\x58\x13\x6D\x4C\xAA\xC1\xAC\x18\xC0\xAB\x49\x5F\xCD\xCB\xEE\x28\x74\x07\xB0\x1F\x07\xE6\x61\x0D\x74\x06\xBA\xC1\x7B\x41\x60\x1E\x9D\x18\x05\xDC\x86\xAE\x1F\x5E\x17\x97\x8A\x35\xC9\x8E\xC0\x52\x34\x83\x76\x31\xF0\xD4\xB8\x54\x3A\xB6\x37\xBA\xA2\x05\xF7\x03\x4F\x8A\x4B\xC5\x9A\x62\x26\xBA\xB3\xCE\xF1\x81\x79\xE4\x72\x39\xBA\xFE\x38\x39\x30\x0F\x6B\x80\x03\xD0\x0D\xD6\xBB\x49\xAB\xFA\x55\xCD\x44\xE0\x51\x34\x7D\xF2\x28\xB0\x75\x5C\x2A\x56\x67\xDD\x68\x57\xF4\x7B\x65\x5C\x2A\xD9\x7D\x04\x5D\xBF\x7C\x2D\x30\x0F\xAB\xB1\x63\xD1\x0D\xD2\x6F\x07\xE6\xA1\xB0\x11\xA9\xD0\x9E\xA2\x6F\xFA\x48\x05\x02\xCD\xDA\xA6\x2C\x93\xB3\x1C\xD8\x29\x2E\x15\x99\xC3\xD1\x1D\xE0\xEE\x44\xBF\x28\xB9\xD5\xD8\x79\xE8\x06\xE7\xA7\x02\xF3\x50\xFB\x3E\xBA\x7E\x9A\x1E\x97\x86\xD5\xC9\x33\x49\x8B\x73\x29\x06\xE5\x42\xE0\xC9\x71\xA9\xC8\xA9\xFB\xCA\xE5\x77\xAC\x65\xCA\xB3\xCA\x51\x81\x79\x44\xF9\x22\xBA\xFE\x3A\x33\x30\x0F\xAB\x81\x29\xE8\x06\xE3\xAF\xA9\xE7\xEF\x3A\x75\xF9\x9D\x3A\x5C\x2F\xB0\x00\x3D\xC0\xBD\x68\x06\x62\xDD\xAF\xAC\xBE\x17\xDD\x81\x6F\x56\x60\x1E\x56\x61\x27\xA3\x1B\x84\x97\x05\xE6\x51\x84\x6E\xE0\x77\xE8\xFA\xAF\xCA\xF7\xCC\x2D\xC0\x56\xE8\xCA\xE4\x3C\x0E\x4C\x8A\x4B\xA5\x30\x7E\x6A\xCD\x0A\x73\x19\xBA\xC1\xF7\xE1\x80\xF8\x7B\x80\x23\x81\xAB\x48\x6B\xF2\xAE\xEC\x6F\x73\xFB\xFF\xED\xC8\xFE\xBF\x51\xBB\x16\x5D\x3F\x1E\x17\x10\xBF\x55\xD0\x5E\xE8\xDE\xB0\x99\x87\xFE\x0D\x9B\xC3\x49\xE5\x78\x86\x8B\x65\x7E\xFF\xDF\x2A\x29\xDF\xDC\x72\xF9\x1D\x7B\x82\x2E\xB4\xEF\xB8\x4E\x11\xC6\x3E\x8A\xF6\xD6\x65\x3A\x07\xED\xD5\xF0\x19\x6D\xC4\x34\xD2\x76\xBE\x30\x6E\xAB\xA0\xE9\xE8\x06\xDB\x4D\xE2\xD8\x3B\x59\x54\xED\x1C\x61\x5C\xCA\xEA\x25\xAB\x80\xE7\x0A\x63\xB7\x0A\xA9\x72\x9D\xA7\x1C\xCF\x21\x2B\xBF\x4E\x4F\xCB\x10\xDF\x50\xED\x56\xCA\x5D\x3F\xCC\x82\x9C\x89\x6E\x90\x9D\x27\x8C\xBB\x87\xF4\xDB\xBA\xD3\x18\xFF\x4C\x7A\xAB\x48\xA1\x0B\xF8\x55\x86\x18\x87\x6A\xAF\x17\xC5\x6D\x15\x51\xE5\x5A\xC7\x47\x66\x8C\xF5\x08\x61\x9C\x4D\xAC\xA1\x6D\x41\xAE\x43\x77\x76\x38\x56\x1C\xFB\xD5\x19\x63\xBD\x5A\x1C\xEB\x57\x33\xC6\x3A\xB8\x9D\x22\x8E\xDD\x4A\xEA\xE5\xE8\x06\xD5\x1C\xF4\x0F\x1C\xE4\xF8\xFA\x3C\xD0\xE6\x89\x63\x6D\xD2\x3A\x52\x16\x40\xBD\xE2\xDE\xC1\x01\x39\xE4\xBC\xCF\xBA\x34\x20\xDE\x93\x32\xC6\x3B\xB8\x7D\x3D\x20\x7E\x2B\x91\xE3\xD1\x0D\xA6\x99\x41\x39\xE4\x8E\x5B\x4D\xFD\x92\xC8\x4B\x03\x72",
				"\xB0\x12\xA8\xCB\xAA\xF3\x55\x9B\xC0\x00\x87\x09\xE2\x1E\x68\xB3\xA9\xE7\x6B\x9A\x36\xC8\x05\xE8\x06\xD1\x8C\xC0\x3C\xAA\x38\x81\x01\x6E\x14\xC4\x3E\xD0\x8E\x0E\xCC\xC3\x0A\xB0\x1B\xF5\x29\xFD\x52\xD5\x09\xBC\x2B\xB0\x42\x10\xFF\x1A\xE0\x41\xEA\x55\xAA\xC8\x06\xB9\x19\xDD\xD1\x7F\x5A\x60\x1E\x64\x8E\x3D\x72\x02\x03\x9C\x9B\x39\xF6\xB5\xDB\x67\x02\xF3\xB0\x40\x53\xD1\x0D\x9A\x22\xCA\x9F\x56\x79\x02\xAB\xCB\xF5\xEE\x1C\x97\x8A\x45\x18\x0D\x3C\x80\x66\xC0\xF4\x01\x2F\x8A\x4B\xE5\xBF\xAA\x3C\x81\x01\xDE\xDD\x61\xBC\xEB\x6B\xD7\x07\xE6\x61\x01\x4E\x45\x37\x58\x2E\x8D\x4B\xE3\xFF\x54\x7D\x02\x77\x03\x77\x75\x10\xEF\x70\x6D\x72\x5C\x2A\xA6\x34\x11\x78\x0C\xCD\x20\x29\x72\x11\xAE\xAA\x4F\x60\x80\xFD\x5B\x8C\xB1\x95\x76\x1F\x31\xD5\x47\x4C\xEC\x0A\x74\x83\xE4\xA4\xC0\x3C\x06\xAB\xC3\x04\x06\xF8\xE6\x30\x71\x75\xD2\xDE\x1F\x98\x87\x09\xD4\x79\x21\xEA\xBA\x4C\xE0\x49\xA4\x82\x7F\x8A\x7D\xF4\x08\xA9\x50\xA1\x55\xD0\x28\xE0\x76\x74\x47\xF7\x43\xE3\x52\x59\xA7\xBA\x4C\x60\x80\xD3\xC9\x9F\xCF\x40\xBB\x30\x30\x0F\xCB\xE8\x68\x74\x83\xE2\xC7\x81\x79\x0C\xA5\x4E\x13\x78\x0C\xF0\x17\xF2\xE7\xB4\x86\xF4\x2E\xF2\x9E\x71\xA9\x58\x0E\xCA\x32\x39\x2B\x81\x67\xC7\xA5\x32\xA4\x3A\x4D\x60\x80\x37\xA3\x3B\xE0\xFE\x1C\x97\xDF\xA9\x94\xB3\xD0\x0D\x06\x65\x21\xB8\x56\xD4\x6D\x02\x77\x01\x3F\x45\xB7\xDF\x94\x55\x47\x2C\xA3\xA7\xA3\x2B\x93\xF3\x30\xB0\x59\x5C\x2A\xEB\x55\xB7\x09\x0C\xB0\x3B\xBA\xF2\x3B\x7F\x05\xC6\xC6\xA5\x62\xED\xBA\x1E\xDD\x51\xFC\x5D\x81\x79\x0C\xA7\x8E\x13\x18\xE0\x62\x74\xFB\xEF\xB4\xB8\x34\xAC\x1D\x07\xA2\xDB\xF9\x7F\x20\x55\xF2\x28\x8B\xBA\x4E\xE0\x2D\x80\x7F\xA3\xD9\x87\xBD\xC0\xF6\x61\x99\x58\x4B\x36\x04\xEE\x41\x37\x81\x0F\x8C\x4B\x65\x44\xEA\x3A\x81\x01\x3E\x84\x6E\x3F\x5E\x15\x98\x87\xB5\xE0\x04\x74\x3B\xFD\x9A\xC0\x3C\x46\xAA\xCE\x13\xB8\x07\xF8\x13\xBA\xFD\xB9\x6F\x5C\x2A\x36\x12\x5B\x00\x8B\xD1\xEC\xEC\xA5\xC0\x0E\x71\xA9\x8C\x58\x2F\xF9\x72\x7C\x3C\x38\xF6\x91\x78\x0D\xBA\x09\xFC\x1B\xD2\xCB\x14\x56\x12\x17\xA1\xDB\xD9\xA7\x07\xE6\xD1\x8A\x2A\x95\x95\x6D\xD7\xF7\xD0\xED\xD7\xB7\x07\xE6\x61\xEB\xF1\x7C\xD2\x1A\x44\x8A\x9D\xFC\x37\xCA\x7B\xEB\xA1\x4A\x85\xDD\xDB\xB5\x0B\xBA\xF2\x3B\xFF\x04\x9E\x12\x97\x8A\x0D\xE5\x27\xE8\x8E\xD2\x6F\x0A\xCC\xA3\x55\x55\x59\x5A\xA5\x53\x67\xA3\xDB\xBF\x9F\x0B\xCC\xC3\xD6\x21\xE7\x20\x1E\xDC\x7E\x41\xB9\x1F\xBF\xAB\xC2\xE2\x66\x39\x8C\x03\x16\xA0\xD9\xC7\x2B\x49\x85\x0E\xAD\x00\xA3\x49\x83\x4F\xB1\x63\x57\x03\x2F\x0C\xCB\xA4\x7D\x65\x5F\x5E\x34\x97\x77\xA0\x3B\x50\xFF\x30\x30\x0F\x5B\xCB\x69\xE8\x76\xEA\xC5\x71\x69\x74\xAC\xAC\x0B\x7C\xE7\x34\x0A\xB8\x03\xDD\xFE\x3E\x24\x2E\x15\x03\xD8\x06\x5D\x99\x9C\x25\xC0\x84\xB8\x54\x3A\x36\x8A\xF6\x26\xF1\x39\x54\x6B\x25\x83\x7D\xD0\x15\x67\x98\x4B\xB9\x7F\x46\xD4\x4E\xCE\x2B\xB0\x83\xDB\x87\x02\xF3\xC8\xE9\x70\xD2\x7A\xB9\xC3\xE5\x37\x9F\x6A\x7C\x6D\x5E\x17\xE5\x7E\xFF\x60\x60\x1E\x8D\xE6\x23\xF1\xD0\x7A\x48\x17\xF6\xAE\x22\xE5\xB2\xB2\xBF\xCD\xED\xFF\xB7\x23\xA9\x76\xA1\xB7\x6D\xF1\x37\xAF\x4A\xF3\x6F\x21\x3B\x0D\xDD\xFE\xAF\xD2\xB5\x8F\x4A\xF2\xD5\x48\xF3\xDD\x87\x8A\xF2\xFD\x40\x1B\xD0\xE4\xFB\xFF\x95\xE5\x27\x72\x6C\x6D\x4D\x7D\x02\xAF\x92\xFC\x4C\xAC\x0D\xD6\xD4\x67\xE0\x2B\xC9\x6F\xA5\xD8\xBA\x28\xDF\x42\xFB\x78\x60\x1E\xB5\x76\x08\xBA\x9D\xE4\xF7\x42\xAB\xAD\x89\xEF\x81\x57\x8A\x2B\x33\xD8\x70\x9A\x56\x89\xA5\x52\x5C\x1B\xC9\x86\xD3\xB4\x5A\x68\x95\xE1\xEA\x84\x36\x52\x4D\xAA\x46\x5A\x19\xAE\x0F\x6C\xAD\x68\x4A\x3D\xF0\x4A\x70\x85\x7E\x6B\x55\x53\x56\xE4\x28\x3D\xAF\x91\x63\xED\x6A\xC2\x9A\x58\xA5\xE7\x55\xEA\xAC\x5D\x4D\x58\x95\xB2\xD4\xBC\x4E\xAC\x75\xEA\x18\x74\x27\x80\x1F\x05\xE6\x51\x49\xCA\x95\xDA\x2F\x0A\xCC\xC3\x8A\x33\x0A\xB8\x1D\xDD\x38\x3A\x34\x2E\x95\x6A\x99\x44\x5A\x21\x40\xD1\xE9\x8F\x00\x5B\xC5\xA5\x62\x05\xDB\x1B\x5D\xD1\x87\xFB\x81\x27\xC5\xA5\x52\x1D\xDF\x44\x77\xD4\x7C\x7F\x60\x1E\x56\x0E\x57\xA0\x1B\x4F\x27\x05\xE6\x51\x09\xFB\xA3\xEB\xEC\xFB\xA8\x76\x19\x19\x6B\xCF\x44\x74\xE5\x77\x1E\x05\xB6\x8E\x4B\xA5\xDC\xBA\x81\xBB\xD0\x4D\xE0\xC9\x71\xA9\x58\xC9\x9C\x8A\x6E\x5C\x5D\x1A\x97\x46\xB9\xBD\x1B\x5D\x27\x5F\x1F\x98\x47\x19\xD4\xBD\xA8\x5D\xAB\x46\x03\x0F\xA0\x19\x5B\x7D\xC0\x8B\xE2\x52\x29\xA7\xF1\xC0\xBF\xD0\x74\xF0\x72\x60",
				"\xE7\xB8\x54\x0A\xD7\x84\xB2\xB2\xED\x98\x8A\xEE\x04\x71\x27\xD5\xAA\xAD\x9D\xDD\xB9\xE8\x3A\xF7\x33\x81\x79\x14\xA9\x29\x85\xDD\x3B\x71\x33\xBA\x71\xF6\xD6\xC0\x3C\x4A\x65\x57\x74\x65\x72\x1E\x04\x9E\x1C\x97\x4A\xA1\x9A\xB0\xB4\x4A\xA7\x76\x23\xFD\x94\x50\x8C\xB5\x85\xA4\x82\x8B\x8D\x73\x23\xBA\xA3\xE2\xD1\x81\x79\x14\xA9\x29\x8B\x9B\xE5\x70\x01\xBA\xF1\x36\x23\x30\x8F\x52\x38\x0C\x5D\x67\xCE\xA6\x19\x5F\x0D\x9B\xB2\xBC\x68\x2E\x9B\x02\x0F\xA1\x19\x73\xCB\x81\x67\xC4\xA5\x52\xAC\x1E\xE0\x5E\x34\x1D\xD9\x07\xBC\x34\x2E\x95\x42\x35\x65\x81\xEF\x9C\x8E\x47\x77\xE2\x98\x19\x98\x47\xA1\x4E\x42\xD7\x89\x5F\x0F\xCC\xA3\x68\x39\x17\xFA\xBA\x3A\x38\xF6\xA2\x6C\x00\xFC\x1E\xDD\xF8\x3B\x38\x2E\x95\x62\x6C\x49\x7A\x2E\x59\xD1\x79\xBD\xC0\x76\x71\xA9\x14\x2E\xC7\xD7\xE7\x81\x36\x2F\x38\xF6\x22\xBD\x1C\xDD\x04\x9E\x43\xAA\xD1\x55\x5B\x5F\x45\xD7\x79\xA7\x04\xE6\x51\x06\x4B\xC9\xD7\x77\x4B\x83\x63\x2F\xDA\x75\xE8\xC6\xE1\xB1\x81\x79\x84\xDA\x03\x5D\x99\x9C\xF9\xA4\x77\x89\x9B\x24\x67\xF9\x98\x65\xC1\xB1\x17\xED\x69\xE8\xCA\xEF\x2C\x02\x36\x8F\x4B\x25\x46\x17\xF0\x33\x74\x47\xBD\xD7\xC7\xA5\x52\x1A\x39\x0B\x1F\xFC\x25\x38\xF6\x32\xF8\x14\xBA\xF1\x78\x5E\x60\x1E\x21\xA6\xA1\xEB\xAC\x5B\x69\x66\x99\x9C\x59\xE4\xEB\xC3\x59\xC1\xB1\x97\x81\xB2\xFC\xCE\x2A\xE0\x39\x71\xA9\x68\x6D\x0C\xFC\x1D\x5D\x47\x3D\x37\x2E\x95\x52\x39\x8A\x7C\xFD\x38\x3D\x36\xF4\xD2\x98\x8E\xEE\xC4\x72\x53\x5C\x1A\x5A\x33\xD0\x75\xD2\xF9\x81\x79\x94\xCD\x58\xD2\x63\x7C\x9D\xF6\xE1\x42\x9A\x5B\x66\xB7\x0B\xB8\x0D\xDD\xF8\x9C\x12\x97\x8A\xC6\x8E\xE4\xBD\x5A\xBA\x76\xAB\xE5\xC5\x82\x16\xE5\x28\xE0\x76\x4C\x78\xD4\xE5\xB2\x17\xBA\xF2\x3B\xF3\xA8\x78\xF9\x9D\x6B\xD1\x1D\xDD\x8E\x0B\xCC\xA3\xCC\xAE\xA4\xFD\x3E\xBC\xB2\x80\x78\xCB\xE8\x32\x74\xE3\xF4\xC3\x81\x79\x64\xB5\x2F\xBA\x4E\xB9\x9B\x9A\xDF\x30\x6F\x41\x0F\xF0\x0D\x5A\xEF\xC3\x6F\xD0\xAC\x97\xFB\xD7\x67\x22\xA9\x4C\x8E\x62\xAC\x3E\x4A\x5A\xE7\xAB\x72\x6E\x41\x37\x81\x0F\x8A\x4B\xA3\x12\xBA\x80\xF7\x32\xB2\xA7\xDC\x1E\xE9\xFF\xDB\x26\x5E\xB9\x5F\x9F\x93\xD1\x8D\xD7\xB3\x02\xF3\xC8\x62\x07\x74\xBF\x2B\xAE\x0B\xCC\xA3\x6A\xC6\x93\xD6\xCB\xFD\x29\xE9\xD1\xD2\x81\x3E\xEB\xED\xFF\xB7\x13\xFA\xFF\xC6\x9E\x68\x23\x74\x2F\xD9\x2C\xA4\x62\x0B\xC9\xAB\x5E\x58\x58\x0E\xEC\x14\x98\x47\xD5\x8D\xC7\x13\xB6\x15\x53\xD0\x9D\x85\xF7\x8B\x4B\xA3\x73\xB3\xD1\x74\xC2\x99\x91\x49\x58\x23\x7D\x1F\xCD\xD8\xFD\x62\x64\x12\x9D\x98\x80\xA6\x03\x16\x90\x9E\x9E\x31\x53\x7A\x36\x9A\xF2\x3B\x95\x79\x5C\xF5\x50\x34\x13\x78\x7A\x60\x0E\xD6\x6C\xE7\xA1\x19\xC3\x95\x58\xDE\xE7\x13\xE4\x4F\xBC\xF1\xE5\x3B\x2D\x94\xAA\xDC\xF1\xAB\x73\x07\xAA\x98\x14\xBB\x67\xDE\xDE\x1A\xD2\x6D\x8F\xBE\xCC\xDB\x35\x1B\xCA\x62\xE0\x63\x82\xED\xEE\x21\xD8\x66\x76\xB9\x4B\x96\x34\xA9\x4C\x8E\x95\xC7\x06\xA4\x07\x86\x72\x8E\xE5\x8B\x73\x07\xA9\x38\x03\xE7\x7E\xEA\xE4\x92\xCC\xDB\x33\x1B\x89\x55\xC0\xE5\x99\xB7\x99\xFD\xD9\xFD\xDC\x13\xB8\x9B\xFC\x41\xDE\x91\x79\x7B\x66\x23\x75\x67\xE6\xED\x95\x7E\x02\x8F\xCD\xBC\xCD\xC7\x48\x8F\xFE\x99\x15\x61\x41\xE6\xED\x65\x5F\x2D\x24\xF7\x04\x6E\x5A\x6D\x25\xAB\xB7\xDC\xCF\x8B\x2F\xCF\xBC\xBD\xEC\x13\x78\x05\x79\xAF\x16\x6F\x8C\x1F\xDE\xB0\xE2\x4C\xC8\xBC\xBD\xC7\x33\x6F\x4F\x72\x11\x2B\x77\x89\xD2\x4A\x5C\x7A\xB7\x5A\xDA\x33\xF3\xF6\x7A\x33\x6F\x4F\x32\x81\x73\x3F\x32\x76\x58\xE6\xED\x99\x8D\x54\xEE\xB1\xB7\x30\xF3\xF6\x24\x13\xF8\xDE\xCC\xDB\x9B\x86\xDF\xA8\xB1\x78\x2F\x21\xFF\x19\x78\x4E\xE6\xED\x55\x62\x02\x8F\x07\x4E\xCF\xBC\x4D\xB3\xF5\xD9\x10\x38\x5B\xB0\xDD\xBB\x05\xDB\xCC\xEE\x8D\xE4\x7F\x86\xB4\x0F\x98\x1A\x99\x84\x35\xDA\xB9\x68\x5E\x66\xD8\x2E\x32\x89\x76\x6D\x81\x66\x09\x95\x65\xC0\x1B\x02\xF3\xB0\xE6\xE9\x26\x9D\x79\x15\x93\x37\xF7\x37\x53\xA9\x5F\xA3\xE9\x84\x3E\xE0\x4B\xB8\x9C\xAC\xE5\xF7\x2C\xD2\x2A\x1F\x8A\x71\xBB\x06\xCD\x57\x72\x99\x33\xD0\x75\xC4\x1A\x52\xA5\xBF\x0B\x49\xAF\x67\xE5\xBE\x57\x67\xCD\x30\x06\xD8\x99\xF4\x9E\xF9\x77\xD1\x2D\xBC\x37\xD0\x24\x85\x18\x55\x95\x09\x77\x02\xEE\x11\x6E\xDF\xAC\x4A\x16\x92\x7E\xFF\xAE\xC8\xBD\x61\xD5\x4B\xF2\xF7\x52\xA3\xB5\x61\xCC\x3A\x74\x21\x82\xC9\x0B\xDA\x52\x97\xBD\xF8\xA2\x93\xD9\x0A\xE0\x2D\xA4\x17\x73\xB2\x53\x96\xA9\x99\x45\x45\xEE\x7B\x99\x09\x5D\x81\xE0\x09\xAC\x01\xEA",
				"\xDF\xA8\xAF\x22\x5D\x20\x30\x6B\xA2\xC7\x80\x5D\x48\xCB\xEB\x4A\xA8\x0B\xC5\x7D\x0F\xF8\xA1\xF8\x33\xCC\xCA\x6A\x06\xC2\xC9\x0B\x31\x57\x89\x77\x21\xDD\x17\x1E\x13\xF0\x59\x66\x65\x31\x97\x54\x63\x5A\xFA\x8E\x7C\xC4\x7A\x2D\x0F\x91\x4A\x74\xBE\x26\xE0\xB3\xCC\xCA\x60\x19\x30\x19\xF8\xAB\xFA\x83\xA2\x16\x5C\x9A\x4D\x7A\xD2\xE5\x99\x41\x9F\x67\x56\xA4\x63\x81\xEB\x23\x3E\x28\xF2\x41\x8B\x71\xC0\xCD\xE4\xAF\x1B\x6D\x56\x26\x97\x02\x47\x45\x7D\x58\xF4\x93\x52\x9B\x93\x96\xB9\xDC\x35\xF8\x73\xCD\x22\xCC\x04\x8E\x20\x95\xA4\x0D\x51\xC4\xA3\x8E\x93\x80\x9F\x00\xDB\x17\xF0\xD9\x66\x2A\xB3\x48\x0F\x2E\xAD\x8C\xFC\xD0\x22\xD6\x1B\x9A\x0F\xEC\x05\xDC\x56\xC0\x67\x9B\x29\x5C\x4A\x3A\xF3\x86\x4E\xDE\xA2\x6D\x44\xAA\x7C\xAF\x7C\x03\xC4\xCD\x4D\xD9\x56\x02\x27\x52\xA0\xA8\xAB\xD0\xEB\xB2\x1A\xB8\x96\x54\x3C\xFB\x65\xA4\x09\x6D\x56\x15\x0F\x00\x53\x48\x8F\x4A\x36\xDE\x24\x74\x2B\xA3\xBB\xB9\xE5\x6C\x2B\x80\x4F\xE2\x07\x93\xD6\x69\x32\x70\x3B\xC5\xEF\x24\x37\xB7\xC1\x6D\x35\xF0\x2D\x60\x37\x6C\x58\x87\x90\xCE\xC8\xAB\x28\x7E\xC7\xB9\x35\xBB\x2D\x05\x2E\x22\x15\xA9\x28\x9D\xB2\x57\xCC\x98\x08\xBC\x99\x74\x79\xFE\x79\x14\xFB\x9B\xDD\x9A\xA3\x97\xF4\x22\xCE\x4C\xD2\xDB\x74\x4B\x8A\x0D\x67\x68\x65\x9F\xC0\x6B\xDB\x04\xD8\x1B\xD8\x87\x54\xCB\x68\x1B\x52\x99\x92\x09\x78\x62\x5B\xEB\x96\x01\x8B\x80\xC5\xC0\xC3\xC0\x1F\x49\x8F\xFC\xFE\x86\xB4\x48\xBD\x17\xEA\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\xAB\x80\xFF\x00\x35\x85\x34\xED\x1E\xFC\xAB\x96\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x4D\x65\x73\x73\x61\x67\x65\x42\x6F\x78\x43\x6F\x6D\x70\x6F\x6E\x65\x6E\x74\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0B\x00\x00\x00\x00\x00\x00\x00\x0B\x00\x00\x00\x50\x72\x65\x63\x6F\x6D\x70\x69\x6C\x65\x64\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x0F\x00\x00\x00\x00\x00\x00\x00\x0F\x00\x00\x00\x43\x6C\x61\x73\x73\x4E\x61\x6D\x65\x52\x65\x63\x6F\x72\x64\x0B\x00\x00\x00\x00\x00\x00\x00\x26\x00\x00\x00\x00\x00\x00\x00\x26\x00\x00\x00\x67\x61\x63\x6C\x69\x62\x5F\x63\x6F\x6E\x74\x72\x6F\x6C\x73\x3A\x3A\x43\x6F\x6C\x6F\x72\x43\x6F\x6D\x70\x6F\x6E\x65\x6E\x74\x43\x6F\x6E\x74\x72\x6F\x6C\x23\x00\x00\x00\x00\x00\x00\x00\x23\x00\x00\x00\x67\x61\x63\x6C\x69\x62\x5F\x63\x6F\x6E\x74\x72\x6F\x6C\x73\x3A\x3A\x43\x6F\x6C\x6F\x72\x44\x69\x61\x6C\x6F\x67\x43\x6F\x6E\x74\x72\x6F\x6C\x22\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x67\x61\x63\x6C\x69\x62\x5F\x63\x6F\x6E\x74\x72\x6F\x6C\x73\x3A\x3A\x43\x6F\x6C\x6F\x72\x44\x69\x61\x6C\x6F\x67\x57\x69\x6E\x64\x6F\x77\x21\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\x67\x61\x63\x6C\x69\x62\x5F\x63\x6F\x6E\x74\x72\x6F\x6C\x73\x3A\x3A\x46\x69\x6C\x65\x44\x69\x61\x6C\x6F\x67\x57\x69\x6E\x64\x6F\x77\x22\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x67\x61\x63\x6C\x69\x62\x5F\x63\x6F\x6E\x74\x72\x6F\x6C\x73\x3A\x3A\x46\x69\x6C\x65\x50\x69\x63\x6B\x65\x72\x43\x6F\x6E\x74\x72\x6F\x6C\x20\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x67\x61\x63\x6C\x69\x62\x5F\x63\x6F\x6E\x74\x72\x6F\x6C\x73\x3A\x3A\x46\x6F\x6E\x74\x4E\x61\x6D\x65\x43\x6F\x6E\x74\x72\x6F\x6C\x20\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x67\x61\x63\x6C\x69\x62\x5F\x63\x6F\x6E\x74\x72\x6F\x6C\x73\x3A\x3A\x46\x6F\x6E\x74\x53\x69\x7A\x65\x43\x6F\x6E\x74\x72\x6F\x6C\x25\x00\x00\x00\x00\x00\x00\x00\x25\x00\x00\x00\x67\x61\x63\x6C\x69\x62\x5F\x63\x6F\x6E\x74\x72\x6F\x6C\x73\x3A\x3A\x46\x75\x6C\x6C\x46\x6F\x6E\x74\x44\x69\x61\x6C\x6F\x67\x57\x69\x6E\x64\x6F\x77\x27\x00\x00\x00\x00\x00\x00\x00\x27\x00\x00\x00\x67\x61\x63\x6C\x69\x62\x5F\x63\x6F\x6E\x74\x72\x6F\x6C\x73\x3A\x3A\x53\x69\x6D\x70\x6C\x65\x46\x6F\x6E\x74\x44\x69\x61\x6C\x6F\x67\x57\x69\x6E\x64\x6F\x77\x29\x00\x00\x00\x00\x00\x00\x00\x29\x00\x00\x00\x67\x61\x63\x6C\x69\x62\x5F",
				"\x63\x6F\x6E\x74\x72\x6F\x6C\x73\x3A\x3A\x4D\x65\x73\x73\x61\x67\x65\x42\x6F\x78\x42\x75\x74\x74\x6F\x6E\x54\x65\x6D\x70\x6C\x61\x74\x65\x21\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\x67\x61\x63\x6C\x69\x62\x5F\x63\x6F\x6E\x74\x72\x6F\x6C\x73\x3A\x3A\x4D\x65\x73\x73\x61\x67\x65\x42\x6F\x78\x57\x69\x6E\x64\x6F\x77\x00\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x55\x6E\x69\x74\x54\x65\x73\x74\x43\x6F\x6E\x66\x69\x67\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x49\x6D\x61\x67\x65\x44\x61\x74\x61\xEF\x01\x00\x00\x00\x00\x00\x00\xEF\x01\x00\x00\x3C\x49\x6D\x61\x67\x65\x44\x61\x74\x61\x3E\x3C\x49\x6D\x61\x67\x65\x20\x50\x61\x74\x68\x3D\x22\x49\x6D\x61\x67\x65\x73\x2F\x4E\x6F\x6E\x65\x22\x20\x46\x6F\x72\x6D\x61\x74\x3D\x22\x50\x6E\x67\x22\x20\x57\x69\x64\x74\x68\x3D\x22\x32\x34\x30\x22\x20\x48\x65\x69\x67\x68\x74\x3D\x22\x32\x34\x30\x22\x2F\x3E\x3C\x49\x6D\x61\x67\x65\x20\x50\x61\x74\x68\x3D\x22\x49\x6D\x61\x67\x65\x73\x2F\x45\x72\x72\x6F\x72\x22\x20\x46\x6F\x72\x6D\x61\x74\x3D\x22\x50\x6E\x67\x22\x20\x57\x69\x64\x74\x68\x3D\x22\x32\x34\x30\x22\x20\x48\x65\x69\x67\x68\x74\x3D\x22\x32\x34\x30\x22\x2F\x3E\x3C\x49\x6D\x61\x67\x65\x20\x50\x61\x74\x68\x3D\x22\x49\x6D\x61\x67\x65\x73\x2F\x51\x75\x65\x73\x74\x69\x6F\x6E\x22\x20\x46\x6F\x72\x6D\x61\x74\x3D\x22\x50\x6E\x67\x22\x20\x57\x69\x64\x74\x68\x3D\x22\x32\x34\x30\x22\x20\x48\x65\x69\x67\x68\x74\x3D\x22\x32\x34\x30\x22\x2F\x3E\x3C\x49\x6D\x61\x67\x65\x20\x50\x61\x74\x68\x3D\x22\x49\x6D\x61\x67\x65\x73\x2F\x57\x61\x72\x6E\x69\x6E\x67\x22\x20\x46\x6F\x72\x6D\x61\x74\x3D\x22\x50\x6E\x67\x22\x20\x57\x69\x64\x74\x68\x3D\x22\x32\x34\x30\x22\x20\x48\x65\x69\x67\x68\x74\x3D\x22\x32\x34\x30\x22\x2F\x3E\x3C\x49\x6D\x61\x67\x65\x20\x50\x61\x74\x68\x3D\x22\x49\x6D\x61\x67\x65\x73\x2F\x49\x6E\x66\x6F\x72\x6D\x61\x74\x69\x6F\x6E\x22\x20\x46\x6F\x72\x6D\x61\x74\x3D\x22\x50\x6E\x67\x22\x20\x57\x69\x64\x74\x68\x3D\x22\x32\x34\x30\x22\x20\x48\x65\x69\x67\x68\x74\x3D\x22\x32\x34\x30\x22\x2F\x3E\x3C\x49\x6D\x61\x67\x65\x20\x50\x61\x74\x68\x3D\x22\x49\x6D\x61\x67\x65\x73\x2F\x46\x69\x6C\x65\x22\x20\x46\x6F\x72\x6D\x61\x74\x3D\x22\x50\x6E\x67\x22\x20\x57\x69\x64\x74\x68\x3D\x22\x32\x34\x30\x22\x20\x48\x65\x69\x67\x68\x74\x3D\x22\x32\x34\x30\x22\x2F\x3E\x3C\x49\x6D\x61\x67\x65\x20\x50\x61\x74\x68\x3D\x22\x49\x6D\x61\x67\x65\x73\x2F\x46\x6F\x6C\x64\x65\x72\x22\x20\x46\x6F\x72\x6D\x61\x74\x3D\x22\x50\x6E\x67\x22\x20\x57\x69\x64\x74\x68\x3D\x22\x32\x34\x30\x22\x20\x48\x65\x69\x67\x68\x74\x3D\x22\x32\x34\x30\x22\x2F\x3E\x3C\x2F\x49\x6D\x61\x67\x65\x44\x61\x74\x61\x3E\x00\x00\x00\x00\x00\x00\x00\x00",
				};

			class GuiFakeDialogServiceUIResourceLoaderPlugin : public Object, public IGuiPlugin
			{
			public:

				GUI_PLUGIN_NAME(GacGen_GuiFakeDialogServiceUIResourceLoader)
				{
					GUI_PLUGIN_DEPEND(GacUI_Res_Resource);
					GUI_PLUGIN_DEPEND(GacUI_Res_TypeResolvers);
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
					GUI_PLUGIN_DEPEND(GacUI_Instance_Reflection);
					GUI_PLUGIN_DEPEND(GacUI_Compiler_WorkflowTypeResolvers);
#endif
				}

				void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
				{
					if (controllerRelatedPlugins)
					{
						List<GuiResourceError> errors;
						MemoryStream resourceStream;
						GuiFakeDialogServiceUIResourceReader::ReadToStream(resourceStream);
						resourceStream.SeekFromBegin(0);
						GetResourceManager()->LoadResourceOrPending(resourceStream, GuiResourceUsage::InstanceClass);
					}
				}

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


/***********************************************************************
.\UTILITIES\SHAREDSERVICES\GUISHAREDASYNCSERVICE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;

/***********************************************************************
SharedAsyncService::TaskItem
***********************************************************************/

		SharedAsyncService::TaskItem::TaskItem()
			:semaphore(0)
		{
		}

		SharedAsyncService::TaskItem::TaskItem(Semaphore* _semaphore, const Func<void()>& _proc)
			:semaphore(_semaphore)
			,proc(_proc)
		{
		}

		SharedAsyncService::TaskItem::~TaskItem()
		{
		}

/***********************************************************************
SharedAsyncService::DelayItem
***********************************************************************/

		SharedAsyncService::DelayItem::DelayItem(SharedAsyncService* _service, const Func<void()>& _proc, bool _executeInMainThread, vint milliseconds)
			:service(_service)
			,proc(_proc)
			,status(INativeDelay::Pending)
			, executeUtcTime(DateTime::UtcTime().Forward(milliseconds))
			,executeInMainThread(_executeInMainThread)
		{
		}

		SharedAsyncService::DelayItem::~DelayItem()
		{
		}

		INativeDelay::ExecuteStatus SharedAsyncService::DelayItem::GetStatus()
		{
			return status;
		}

		bool SharedAsyncService::DelayItem::Delay(vint milliseconds)
		{
			SPIN_LOCK(service->taskListLock)
			{
				if(status==INativeDelay::Pending)
				{
					executeUtcTime =DateTime::UtcTime().Forward(milliseconds);
					return true;
				}
			}
			return false;
		}

		bool SharedAsyncService::DelayItem::Cancel()
		{
			SPIN_LOCK(service->taskListLock)
			{
				if(status==INativeDelay::Pending)
				{
					if(service->delayItems.Remove(this))
					{
						status=INativeDelay::Canceled;
						return true;
					}
				}
			}
			return false;
		}

/***********************************************************************
SharedAsyncService
***********************************************************************/

		SharedAsyncService::SharedAsyncService()
			:mainThreadId(Thread::GetCurrentThreadId())
		{
		}

		SharedAsyncService::~SharedAsyncService()
		{
		}

		void SharedAsyncService::ExecuteAsyncTasks()
		{
			auto now=DateTime::UtcTime();
			Array<TaskItem> items;
			List<Ptr<DelayItem>> executableDelayItems;

			SPIN_LOCK(taskListLock)
			{
				CopyFrom(items, taskItems);
				taskItems.RemoveRange(0, items.Count());
				// TODO: (enumerable) foreach:indexed(alterable(reversed))
				for(vint i=delayItems.Count()-1;i>=0;i--)
				{
					Ptr<DelayItem> item=delayItems[i];
					if(now >= item->executeUtcTime)
					{
						item->status=INativeDelay::Executing;
						executableDelayItems.Add(item);
						delayItems.RemoveAt(i);
					}
				}
			}

			for (auto item : items)
			{
				item.proc();
				if(item.semaphore)
				{
					item.semaphore->Release();
				}
			}
			for (auto item : executableDelayItems)
			{
				if(item->executeInMainThread)
				{
					item->proc();
					item->status=INativeDelay::Executed;
				}
				else
				{
					InvokeAsync([=]()
					{
						item->proc();
						item->status=INativeDelay::Executed;
					});
				}
			}
		}

		bool SharedAsyncService::IsInMainThread(INativeWindow* window)
		{
			return Thread::GetCurrentThreadId()==mainThreadId;
		}

		void SharedAsyncService::InvokeAsync(const Func<void()>& proc)
		{
			ThreadPoolLite::Queue(proc);
		}

		void SharedAsyncService::InvokeInMainThread(INativeWindow* window, const Func<void()>& proc)
		{
			SPIN_LOCK(taskListLock)
			{
				TaskItem item(0, proc);
				taskItems.Add(item);
			}
		}

		bool SharedAsyncService::InvokeInMainThreadAndWait(INativeWindow* window, const Func<void()>& proc, vint milliseconds)
		{
			Semaphore semaphore;
			semaphore.Create(0, 1);

			SPIN_LOCK(taskListLock)
			{
				TaskItem item(&semaphore, proc);
				taskItems.Add(item);
			}

#ifdef VCZH_MSVC
			if(milliseconds<0)
			{
				return semaphore.Wait();
			}
			else
			{
				return semaphore.WaitForTime(milliseconds);
			}
#else
			return semaphore.Wait();
#endif
		}

		Ptr<INativeDelay> SharedAsyncService::DelayExecute(const Func<void()>& proc, vint milliseconds)
		{
			Ptr<DelayItem> delay;
			SPIN_LOCK(taskListLock)
			{
				delay=Ptr(new DelayItem(this, proc, false, milliseconds));
				delayItems.Add(delay);
			}
			return delay;
		}

		Ptr<INativeDelay> SharedAsyncService::DelayExecuteInMainThread(const Func<void()>& proc, vint milliseconds)
		{
			Ptr<DelayItem> delay;
			SPIN_LOCK(taskListLock)
			{
				delay=Ptr(new DelayItem(this, proc, true, milliseconds));
				delayItems.Add(delay);
			}
			return delay;
		}
	}
}

/***********************************************************************
.\UTILITIES\SHAREDSERVICES\GUISHAREDAUTOMATIONSERVICE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace remoteprotocol;

/***********************************************************************
DumpRemoteProtocolRenderingDom
***********************************************************************/

		Ptr<glr::json::JsonNode> DumpRemoteProtocolRenderingDom(
			const WString& title,
			const remoteprotocol::WindowSizingConfig& windowSizingConfig,
			Ptr<remoteprotocol::RenderingDom> renderingDom,
			collections::Dictionary<vint, collections::Pair<remoteprotocol::RendererType, Nullable<remoteprotocol::UnitTest_ElementDescVariant>>>& elementData
		)
		{
			auto dumpRoot = Ptr(new glr::json::JsonObject);
			ConvertCustomTypeToJsonField(dumpRoot, L"Title", title);
			ConvertCustomTypeToJsonField(dumpRoot, L"Window", windowSizingConfig);

			{
				auto field = Ptr(new glr::json::JsonObjectField);
				field->name.value = WString::Unmanaged(L"Elements");

				auto jsonArray = Ptr(new glr::json::JsonArray);
				field->value = jsonArray;
				dumpRoot->fields.Add(field);

				for (auto [id, data] : elementData)
				{
					auto jsonElement = Ptr(new glr::json::JsonObject);
					jsonArray->items.Add(jsonElement);

					ConvertCustomTypeToJsonField<vint>(jsonElement, L"Id", id);
					ConvertCustomTypeToJsonField(jsonElement, L"Type", data.key);
					ConvertCustomTypeToJsonField(jsonElement, L"Data", data.value);
				}
			}

			if (renderingDom)
			{
				ConvertCustomTypeToJsonField(dumpRoot, L"Dom", renderingDom);
			}
			return dumpRoot;
		}

		WString DumpJsonToString(Ptr<glr::json::JsonNode> json)
		{
			return stream::GenerateToStream([=](stream::TextWriter& writer)
			{
				glr::json::JsonFormatting formatting;
				formatting.spaceAfterColon = true;
				formatting.spaceAfterComma = true;
				formatting.crlf = true;
				formatting.compact = true;
				formatting.indentation = L"  ";
				return glr::json::JsonPrint(json, writer, formatting);
			});
		}

/***********************************************************************
AutomationServiceRenderer
***********************************************************************/

		Nullable<WString> AutomationServiceRenderer::CopyFatalError()
		{
			Nullable<WString> copiedFatalError;
			SPIN_LOCK(lockFatalError)
			{
				copiedFatalError = fatalError;
			}
			return copiedFatalError;
		}

		void AutomationServiceRenderer::SetFatalError(Nullable<WString> value)
		{
			SPIN_LOCK(lockFatalError)
			{
				fatalError = value;
			}
		}

		WString AutomationServiceRenderer::DumpDomTreeInternal()
		{
			auto copiedFatalError = CopyFatalError();
			auto dumpRoot = DumpRemoteProtocolRenderingDom(
				GetCurrentController()->WindowService()->GetMainWindow()->GetTitle(),
				renderer->windowSizingConfig,
				renderer->renderingDom,
				renderer->renderingElements);
			if (copiedFatalError)
			{
				ConvertCustomTypeToJsonField(dumpRoot.Cast<glr::json::JsonObject>(), L"fatalError", copiedFatalError.Value());
			}
			return DumpJsonToString(dumpRoot);
		}

		INativeAutomationService::IOCommandAvailability AutomationServiceRenderer::CanRunIOCommands()
		{
			return CopyFatalError() ? INativeAutomationService::IOCommandAvailability::ExitOnly : INativeAutomationService::IOCommandAvailability::Enabled;
		}

/***********************************************************************
RunIOCommandOnNativeWindow
***********************************************************************/

		namespace iocommands
		{
			const wchar_t* IO_COMMAND_SYNTAX =
				L"Syntax Error!\r\n"
				L"Predefined Commands:\r\n"
				L"!Type:<TEXT>\r\n"
				L"!Exit\r\n"
				L"!KeyDown:Key1+Key2+...+KeyN\r\n"
				L"!KeyUp:Key1+Key2+...+KeyN\r\n"
				L"!KeyPress:Key1+Key2+...+KeyN\r\n"
				L"!MouseMove:X,Y(,ctrl)?(,shift)?(,alt)?\r\n"
				L"!(Left|Middle|Right)(Down|Up|Click|DbClick):X,Y(,ctrl)?(,shift)?(,alt)?\r\n"
				L"!MouseWheel(Up|Down|Left|Right):ticks(,ctrl)?(,shift)?(,alt)?";

			struct IOCommandModifiers
			{
				bool ctrl = false;
				bool shift = false;
				bool alt = false;
			};

			struct TemporaryModifiers
			{
				bool ctrl = false;
				bool shift = false;
				bool alt = false;
			};

			struct MouseCommandArguments
			{
				Point position;
				IOCommandModifiers modifiers;
			};

			struct WheelCommandArguments
			{
				vint ticks = 0;
				IOCommandModifiers modifiers;
			};

			enum class MouseButton
			{
				Left,
				Middle,
				Right,
			};

			struct SyntaxErrorCommand
			{
			};

			struct ExitCommand
			{
			};

			struct TypeCommand
			{
				WString text;
			};

			enum class KeyOperation
			{
				Down,
				Up,
				Press,
			};

			struct KeyCommand
			{
				KeyOperation operation = KeyOperation::Press;
				collections::List<VKEY> keys;
			};

			struct MouseMoveCommand
			{
				MouseCommandArguments arguments;
			};

			struct MouseButtonCommand
			{
				MouseButton button = MouseButton::Left;
				WString operation;
				MouseCommandArguments arguments;
			};

			struct WheelCommand
			{
				vint direction = 0;
				bool horizontal = false;
				WheelCommandArguments arguments;
			};

			using IOCommand = Variant<
				SyntaxErrorCommand,
				ExitCommand,
				TypeCommand,
				KeyCommand,
				MouseMoveCommand,
				MouseButtonCommand,
				WheelCommand
				>;

			struct IOCommandHolder : Object
			{
				IOCommand command;

				IOCommandHolder(IOCommand&& _command)
					: command(std::move(_command))
				{
				}
			};

			bool StartsWith(const WString& text, const WString& prefix)
			{
				return text.Length() >= prefix.Length() && text.Left(prefix.Length()) == prefix;
			}

			WString Trim(const WString& text)
			{
				vint begin = 0;
				vint end = text.Length();
				while (begin < end && (text[begin] == L' ' || text[begin] == L'\t')) begin++;
				while (begin < end && (text[end - 1] == L' ' || text[end - 1] == L'\t')) end--;
				return text.Sub(begin, end - begin);
			}

			WString ToUpperToken(const WString& text)
			{
				WString result;
				for (vint i = 0; i < text.Length(); i++)
				{
					auto ch = text[i];
					if (L'a' <= ch && ch <= L'z') ch = ch - L'a' + L'A';
					result += WString::FromChar(ch);
				}
				return result;
			}

			WString NormalizeKeyName(const WString& text)
			{
				WString result;
				for (vint i = 0; i < text.Length(); i++)
				{
					auto ch = text[i];
					if (ch == L' ' || ch == L'\t') continue;
					if (L'a' <= ch && ch <= L'z') ch = ch - L'a' + L'A';
					result += WString::FromChar(ch);
				}
				return result;
			}

			void SplitByChar(const WString& text, wchar_t delimiter, collections::List<WString>& fragments)
			{
				vint begin = 0;
				for (vint i = 0; i <= text.Length(); i++)
				{
					if (i == text.Length() || text[i] == delimiter)
					{
						fragments.Add(Trim(text.Sub(begin, i - begin)));
						begin = i + 1;
					}
				}
			}

			bool TryParseInteger(const WString& text, vint& value)
			{
				auto normalized = Trim(text);
				if (normalized.Length() == 0) return false;
				value = wtoi(normalized);
				return itow(value) == normalized;
			}

			bool TryParseModifier(const WString& text, IOCommandModifiers& modifiers)
			{
				auto token = ToUpperToken(Trim(text));
				if (token == L"CTRL" || token == L"CONTROL")
				{
					modifiers.ctrl = true;
					return true;
				}
				else if (token == L"SHIFT")
				{
					modifiers.shift = true;
					return true;
				}
				else if (token == L"ALT" || token == L"MENU")
				{
					modifiers.alt = true;
					return true;
				}
				return false;
			}

			bool TryParseMouseArguments(const WString& text, MouseCommandArguments& arguments)
			{
				collections::List<WString> fragments;
				SplitByChar(text, L',', fragments);
				if (fragments.Count() < 2) return false;

				vint x = 0;
				vint y = 0;
				if (!TryParseInteger(fragments[0], x)) return false;
				if (!TryParseInteger(fragments[1], y)) return false;
				arguments.position = Point(x, y);

				for (vint i = 2; i < fragments.Count(); i++)
				{
					if (!TryParseModifier(fragments[i], arguments.modifiers)) return false;
				}
				return true;
			}

			bool TryParseWheelArguments(const WString& text, WheelCommandArguments& arguments)
			{
				collections::List<WString> fragments;
				SplitByChar(text, L',', fragments);
				if (fragments.Count() < 1) return false;
				if (!TryParseInteger(fragments[0], arguments.ticks)) return false;
				if (arguments.ticks < 0) return false;

				for (vint i = 1; i < fragments.Count(); i++)
				{
					if (!TryParseModifier(fragments[i], arguments.modifiers)) return false;
				}
				return true;
			}

			bool IsPressing(IoCommandState* state, VKEY key)
			{
				return state->pressingKeys.Contains(key);
			}

			bool IsCtrlPressing(IoCommandState* state)
			{
				return IsPressing(state, VKEY::KEY_CONTROL) || IsPressing(state, VKEY::KEY_LCONTROL) || IsPressing(state, VKEY::KEY_RCONTROL);
			}

			bool IsShiftPressing(IoCommandState* state)
			{
				return IsPressing(state, VKEY::KEY_SHIFT) || IsPressing(state, VKEY::KEY_LSHIFT) || IsPressing(state, VKEY::KEY_RSHIFT);
			}

			bool IsAltPressing(IoCommandState* state)
			{
				return IsPressing(state, VKEY::KEY_MENU) || IsPressing(state, VKEY::KEY_LMENU) || IsPressing(state, VKEY::KEY_RMENU);
			}

			NativeWindowMouseInfo MakeMouseInfo(IoCommandState* state)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::RunIOCommandOnNativeWindow(...)#"
				CHECK_ERROR(state->mousePosition, ERROR_MESSAGE_PREFIX L"The mouse position is not set.");
				NativeWindowMouseInfo info;
				info.ctrl = IsCtrlPressing(state);
				info.shift = IsShiftPressing(state);
				info.left = state->leftPressing;
				info.middle = state->middlePressing;
				info.right = state->rightPressing;
				info.x = state->mousePosition.Value().x;
				info.y = state->mousePosition.Value().y;
				info.wheel = 0;
				info.nonClient = false;
				return info;
#undef ERROR_MESSAGE_PREFIX
			}

			NativeWindowKeyInfo MakeKeyInfo(IoCommandState* state, VKEY key, bool autoRepeatKeyDown = false)
			{
				NativeWindowKeyInfo info;
				info.code = key;
				info.ctrl = IsCtrlPressing(state);
				info.shift = IsShiftPressing(state);
				info.alt = IsAltPressing(state);
				info.capslock = state->capslockToggled;
				info.autoRepeatKeyDown = autoRepeatKeyDown;
				return info;
			}

			NativeWindowCharInfo MakeCharInfo(IoCommandState* state, wchar_t ch)
			{
				NativeWindowCharInfo info;
				info.code = ch;
				info.ctrl = IsCtrlPressing(state);
				info.shift = IsShiftPressing(state);
				info.alt = IsAltPressing(state);
				info.capslock = state->capslockToggled;
				return info;
			}

			void KeyDown(IoCommandState* state, collections::List<INativeWindowListener*>& listeners, VKEY key)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::RunIOCommandOnNativeWindow(...)#"
				CHECK_ERROR(!IsPressing(state, key), ERROR_MESSAGE_PREFIX L"The key is already being pressed.");
				state->pressingKeys.Add(key);
				if (key == VKEY::KEY_CAPITAL)
				{
					state->capslockToggled = !state->capslockToggled;
				}
				auto info = MakeKeyInfo(state, key);
				for (auto listener : listeners)
				{
					listener->KeyDown(info);
				}
#undef ERROR_MESSAGE_PREFIX
			}

			void KeyUp(IoCommandState* state, collections::List<INativeWindowListener*>& listeners, VKEY key)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::RunIOCommandOnNativeWindow(...)#"
				CHECK_ERROR(IsPressing(state, key), ERROR_MESSAGE_PREFIX L"The key is not being pressed.");
				state->pressingKeys.Remove(key);
				auto info = MakeKeyInfo(state, key);
				for (auto listener : listeners)
				{
					listener->KeyUp(info);
				}
#undef ERROR_MESSAGE_PREFIX
			}

			void Char(IoCommandState* state, collections::List<INativeWindowListener*>& listeners, wchar_t ch)
			{
				auto info = MakeCharInfo(state, ch);
				for (auto listener : listeners)
				{
					listener->Char(info);
				}
			}

			void PressTemporaryModifiers(IoCommandState* state, collections::List<INativeWindowListener*>& listeners, const IOCommandModifiers& modifiers, TemporaryModifiers& temporary)
			{
				if (modifiers.ctrl && !IsCtrlPressing(state))
				{
					KeyDown(state, listeners, VKEY::KEY_CONTROL);
					temporary.ctrl = true;
				}
				if (modifiers.shift && !IsShiftPressing(state))
				{
					KeyDown(state, listeners, VKEY::KEY_SHIFT);
					temporary.shift = true;
				}
				if (modifiers.alt && !IsAltPressing(state))
				{
					KeyDown(state, listeners, VKEY::KEY_MENU);
					temporary.alt = true;
				}
			}

			void ReleaseTemporaryModifiers(IoCommandState* state, collections::List<INativeWindowListener*>& listeners, const TemporaryModifiers& temporary)
			{
				if (temporary.alt)
				{
					KeyUp(state, listeners, VKEY::KEY_MENU);
				}
				if (temporary.shift)
				{
					KeyUp(state, listeners, VKEY::KEY_SHIFT);
				}
				if (temporary.ctrl)
				{
					KeyUp(state, listeners, VKEY::KEY_CONTROL);
				}
			}

			NativePoint ConvertGuiPointToNativePoint(INativeWindow* targetWindow, Point position)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::RunIOCommandOnNativeWindow(...)#"
				CHECK_ERROR(targetWindow, ERROR_MESSAGE_PREFIX L"Native target window is missing.");
				return targetWindow->Convert(position);
#undef ERROR_MESSAGE_PREFIX
			}

			void MouseMove(IoCommandState* state, collections::List<INativeWindowListener*>& listeners, NativePoint position)
			{
				if (!state->mousePosition)
				{
					for (auto listener : listeners)
					{
						listener->MouseEntered();
					}
				}
				else if (state->mousePosition.Value() == position)
				{
					return;
				}

				state->mousePosition = position;
				auto info = MakeMouseInfo(state);
				for (auto listener : listeners)
				{
					listener->MouseMoving(info);
				}
			}

			void ButtonDown(IoCommandState* state, collections::List<INativeWindowListener*>& listeners, MouseButton button, NativePoint position)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::RunIOCommandOnNativeWindow(...)#"
				MouseMove(state, listeners, position);
				switch (button)
				{
				case MouseButton::Left:
					CHECK_ERROR(!state->leftPressing, ERROR_MESSAGE_PREFIX L"The left button should not be being pressed.");
					state->leftPressing = true;
					for (auto listener : listeners) listener->LeftButtonDown(MakeMouseInfo(state));
					break;
				case MouseButton::Middle:
					CHECK_ERROR(!state->middlePressing, ERROR_MESSAGE_PREFIX L"The middle button should not be being pressed.");
					state->middlePressing = true;
					for (auto listener : listeners) listener->MiddleButtonDown(MakeMouseInfo(state));
					break;
				case MouseButton::Right:
					CHECK_ERROR(!state->rightPressing, ERROR_MESSAGE_PREFIX L"The right button should not be being pressed.");
					state->rightPressing = true;
					for (auto listener : listeners) listener->RightButtonDown(MakeMouseInfo(state));
					break;
				}
#undef ERROR_MESSAGE_PREFIX
			}

			void ButtonUp(IoCommandState* state, collections::List<INativeWindowListener*>& listeners, MouseButton button, NativePoint position)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::RunIOCommandOnNativeWindow(...)#"
				MouseMove(state, listeners, position);
				switch (button)
				{
				case MouseButton::Left:
					CHECK_ERROR(state->leftPressing, ERROR_MESSAGE_PREFIX L"The left button should be being pressed.");
					state->leftPressing = false;
					for (auto listener : listeners) listener->LeftButtonUp(MakeMouseInfo(state));
					break;
				case MouseButton::Middle:
					CHECK_ERROR(state->middlePressing, ERROR_MESSAGE_PREFIX L"The middle button should be being pressed.");
					state->middlePressing = false;
					for (auto listener : listeners) listener->MiddleButtonUp(MakeMouseInfo(state));
					break;
				case MouseButton::Right:
					CHECK_ERROR(state->rightPressing, ERROR_MESSAGE_PREFIX L"The right button should be being pressed.");
					state->rightPressing = false;
					for (auto listener : listeners) listener->RightButtonUp(MakeMouseInfo(state));
					break;
				}
#undef ERROR_MESSAGE_PREFIX
			}

			void ButtonDoubleClick(IoCommandState* state, collections::List<INativeWindowListener*>& listeners, MouseButton button, NativePoint position)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::RunIOCommandOnNativeWindow(...)#"
				MouseMove(state, listeners, position);
				switch (button)
				{
				case MouseButton::Left:
					CHECK_ERROR(!state->leftPressing, ERROR_MESSAGE_PREFIX L"The left button should not be being pressed.");
					state->leftPressing = true;
					for (auto listener : listeners) listener->LeftButtonDoubleClick(MakeMouseInfo(state));
					break;
				case MouseButton::Middle:
					CHECK_ERROR(!state->middlePressing, ERROR_MESSAGE_PREFIX L"The middle button should not be being pressed.");
					state->middlePressing = true;
					for (auto listener : listeners) listener->MiddleButtonDoubleClick(MakeMouseInfo(state));
					break;
				case MouseButton::Right:
					CHECK_ERROR(!state->rightPressing, ERROR_MESSAGE_PREFIX L"The right button should not be being pressed.");
					state->rightPressing = true;
					for (auto listener : listeners) listener->RightButtonDoubleClick(MakeMouseInfo(state));
					break;
				}
#undef ERROR_MESSAGE_PREFIX
			}

			void MouseButtonOperation(IoCommandState* state, collections::List<INativeWindowListener*>& listeners, MouseButton button, const WString& operation, NativePoint position)
			{
				if (operation == L"Down")
				{
					ButtonDown(state, listeners, button, position);
				}
				else if (operation == L"Up")
				{
					ButtonUp(state, listeners, button, position);
				}
				else if (operation == L"Click")
				{
					ButtonDown(state, listeners, button, position);
					ButtonUp(state, listeners, button, position);
				}
				else if (operation == L"DbClick")
				{
					ButtonDown(state, listeners, button, position);
					ButtonUp(state, listeners, button, position);
					ButtonDoubleClick(state, listeners, button, position);
					ButtonUp(state, listeners, button, position);
				}
			}

			void Wheel(IoCommandState* state, collections::List<INativeWindowListener*>& listeners, vint wheel, bool horizontal)
			{
				auto info = MakeMouseInfo(state);
				info.wheel = wheel;
				for (auto listener : listeners)
				{
					if (horizontal)
					{
						listener->HorizontalWheel(info);
					}
					else
					{
						listener->VerticalWheel(info);
					}
				}
			}

			bool TryParseKey(INativeController* nativeController, const WString& text, VKEY& key)
			{
				auto token = Trim(text);
				if (token.Length() == 0) return false;
				if (!nativeController) return false;

				auto inputService = nativeController->InputService();
				key = inputService->GetKey(token);
				if (key != VKEY::KEY_UNKNOWN) return true;

				auto normalizedToken = NormalizeKeyName(token);
				for (vint i = 0; i <= (vint)VKEY::KEY_MAXIMUM; i++)
				{
					auto candidate = (VKEY)i;
					auto candidateName = inputService->GetKeyName(candidate);
					if (candidateName != WString::Empty && candidateName != L"?" && NormalizeKeyName(candidateName) == normalizedToken)
					{
						key = candidate;
						return true;
					}
				}
				key = VKEY::KEY_UNKNOWN;
				return false;
			}

			bool TryParseKeyList(INativeController* nativeController, const WString& text, collections::List<VKEY>& keys)
			{
				collections::List<WString> fragments;
				SplitByChar(text, L'+', fragments);
				if (fragments.Count() == 0) return false;
				for (auto fragment : fragments)
				{
					VKEY key = VKEY::KEY_UNKNOWN;
					if (!TryParseKey(nativeController, fragment, key)) return false;
					keys.Add(key);
				}
				return true;
			}

			WString MouseButtonPrefix(MouseButton button)
			{
				switch (button)
				{
				case MouseButton::Left: return WString::Unmanaged(L"!Left");
				case MouseButton::Middle: return WString::Unmanaged(L"!Middle");
				default: return WString::Unmanaged(L"!Right");
				}
			}

			bool TryParseMouseButtonCommand(const WString& command, MouseButton button, const WString& operation, MouseButtonCommand& mouseCommand, bool& matched)
			{
				auto prefix = MouseButtonPrefix(button) + operation + WString::Unmanaged(L":");
				if (!StartsWith(command, prefix)) return false;
				matched = true;

				MouseCommandArguments arguments;
				if (!TryParseMouseArguments(command.Right(command.Length() - prefix.Length()), arguments)) return false;

				mouseCommand.button = button;
				mouseCommand.operation = operation;
				mouseCommand.arguments = arguments;
				return true;
			}

			bool TryParseWheelCommand(const WString& command, const WString& prefix, vint direction, bool horizontal, WheelCommand& wheelCommand, bool& matched)
			{
				if (!StartsWith(command, prefix)) return false;
				matched = true;

				WheelCommandArguments arguments;
				if (!TryParseWheelArguments(command.Right(command.Length() - prefix.Length()), arguments)) return false;

				wheelCommand.direction = direction;
				wheelCommand.horizontal = horizontal;
				wheelCommand.arguments = arguments;
				return true;
			}

			IOCommand ParseIOCommand(INativeController* nativeController, const WString& command)
			{
				if (command == L"!Exit")
				{
					return ExitCommand{};
				}

				if (StartsWith(command, L"!Type:"))
				{
					TypeCommand typeCommand;
					typeCommand.text = command.Right(command.Length() - 6);
					return typeCommand;
				}

				if (StartsWith(command, L"!KeyDown:") || StartsWith(command, L"!KeyUp:") || StartsWith(command, L"!KeyPress:"))
				{
					WString prefix;
					KeyOperation operation = KeyOperation::Press;
					if (StartsWith(command, L"!KeyDown:"))
					{
						prefix = WString::Unmanaged(L"!KeyDown:");
						operation = KeyOperation::Down;
					}
					else if (StartsWith(command, L"!KeyUp:"))
					{
						prefix = WString::Unmanaged(L"!KeyUp:");
						operation = KeyOperation::Up;
					}
					else
					{
						prefix = WString::Unmanaged(L"!KeyPress:");
					}

					collections::List<VKEY> keys;
					if (!TryParseKeyList(nativeController, command.Right(command.Length() - prefix.Length()), keys))
					{
						return SyntaxErrorCommand{};
					}

					KeyCommand keyCommand;
					keyCommand.operation = operation;
					CopyFrom(keyCommand.keys, keys);
					return keyCommand;
				}

				if (StartsWith(command, L"!MouseMove:"))
				{
					MouseMoveCommand mouseCommand;
					if (!TryParseMouseArguments(command.Right(command.Length() - 11), mouseCommand.arguments))
					{
						return SyntaxErrorCommand{};
					}
					return mouseCommand;
				}

				const WString operations[] =
				{
					WString::Unmanaged(L"Down"),
					WString::Unmanaged(L"Up"),
					WString::Unmanaged(L"Click"),
					WString::Unmanaged(L"DbClick"),
				};

				for (auto operation : operations)
				{
					MouseButtonCommand mouseCommand;
					bool matched = false;
					if (TryParseMouseButtonCommand(command, MouseButton::Left, operation, mouseCommand, matched)) return mouseCommand;
					if (matched) return SyntaxErrorCommand{};

					if (TryParseMouseButtonCommand(command, MouseButton::Middle, operation, mouseCommand, matched)) return mouseCommand;
					if (matched) return SyntaxErrorCommand{};

					if (TryParseMouseButtonCommand(command, MouseButton::Right, operation, mouseCommand, matched)) return mouseCommand;
					if (matched) return SyntaxErrorCommand{};
				}

				{
					WheelCommand wheelCommand;
					bool matched = false;
					if (TryParseWheelCommand(command, L"!MouseWheelUp:", 1, false, wheelCommand, matched)) return wheelCommand;
					if (matched) return SyntaxErrorCommand{};
					if (TryParseWheelCommand(command, L"!MouseWheelDown:", -1, false, wheelCommand, matched)) return wheelCommand;
					if (matched) return SyntaxErrorCommand{};
					if (TryParseWheelCommand(command, L"!MouseWheelRight:", 1, true, wheelCommand, matched)) return wheelCommand;
					if (matched) return SyntaxErrorCommand{};
					if (TryParseWheelCommand(command, L"!MouseWheelLeft:", -1, true, wheelCommand, matched)) return wheelCommand;
					if (matched) return SyntaxErrorCommand{};
				}

				return SyntaxErrorCommand{};
			}

			void ExecuteIOCommand(IoCommandState* state, INativeController* nativeController, INativeWindow* targetWindow, collections::List<INativeWindowListener*>& listeners, IOCommand&& ioCommand)
			{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::RunIOCommandOnNativeWindow(...)#"
				CHECK_ERROR(nativeController, ERROR_MESSAGE_PREFIX L"Native controller is missing.");
				CHECK_ERROR(targetWindow, ERROR_MESSAGE_PREFIX L"Native target window is missing.");
				auto listenerList = &listeners;
				auto commandHolder = Ptr(new IOCommandHolder(std::move(ioCommand)));
				nativeController->AsyncService()->InvokeInMainThread(targetWindow, [=]() mutable
				{
					auto activateTargetWindow = [=]()
					{
						if (!targetWindow->IsActivated())
						{
							targetWindow->SetActivate();
						}
					};

					commandHolder->command.Apply(Overloading(
						[](const SyntaxErrorCommand&)
						{
							CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Syntax error command should not be executed.");
						},
						[=](const ExitCommand&)
						{
							targetWindow->Hide(true);
						},
						[=](const TypeCommand& typeCommand)
						{
							activateTargetWindow();
							for (vint i = 0; i < typeCommand.text.Length(); i++)
							{
								auto ch = typeCommand.text[i];
								if (ch == L'\r') continue;
								if (ch == L'\n')
								{
									Char(state, *listenerList, L'\r');
									Char(state, *listenerList, L'\n');
								}
								else
								{
									Char(state, *listenerList, ch);
								}
							}
						},
						[=](const KeyCommand& keyCommand)
						{
							activateTargetWindow();
							switch (keyCommand.operation)
							{
							case KeyOperation::Down:
								for (auto key : keyCommand.keys)
								{
									KeyDown(state, *listenerList, key);
								}
								break;
							case KeyOperation::Up:
								for (vint i = keyCommand.keys.Count() - 1; i >= 0; i--)
								{
									KeyUp(state, *listenerList, keyCommand.keys[i]);
								}
								break;
							case KeyOperation::Press:
								for (auto key : keyCommand.keys)
								{
									KeyDown(state, *listenerList, key);
								}
								for (vint i = keyCommand.keys.Count() - 1; i >= 0; i--)
								{
									KeyUp(state, *listenerList, keyCommand.keys[i]);
								}
								break;
							}
						},
						[=](const MouseMoveCommand& mouseCommand)
						{
							activateTargetWindow();
							TemporaryModifiers temporary;
							PressTemporaryModifiers(state, *listenerList, mouseCommand.arguments.modifiers, temporary);
							MouseMove(state, *listenerList, ConvertGuiPointToNativePoint(targetWindow, mouseCommand.arguments.position));
							ReleaseTemporaryModifiers(state, *listenerList, temporary);
						},
						[=](const MouseButtonCommand& mouseCommand)
						{
							activateTargetWindow();
							TemporaryModifiers temporary;
							PressTemporaryModifiers(state, *listenerList, mouseCommand.arguments.modifiers, temporary);
							MouseButtonOperation(state, *listenerList, mouseCommand.button, mouseCommand.operation, ConvertGuiPointToNativePoint(targetWindow, mouseCommand.arguments.position));
							ReleaseTemporaryModifiers(state, *listenerList, temporary);
						},
						[=](const WheelCommand& wheelCommand)
						{
							activateTargetWindow();
							TemporaryModifiers temporary;
							PressTemporaryModifiers(state, *listenerList, wheelCommand.arguments.modifiers, temporary);
							Wheel(state, *listenerList, wheelCommand.arguments.ticks * 120 * wheelCommand.direction, wheelCommand.horizontal);
							ReleaseTemporaryModifiers(state, *listenerList, temporary);
						}
						));
				});
#undef ERROR_MESSAGE_PREFIX
			}
		}

		WString RunIOCommandOnNativeWindow(
			IoCommandState* state,
			INativeController* nativeController,
			INativeWindow* nativeWindow,
			collections::List<INativeWindowListener*>& listeners,
			WString command
		)
		{
#define ERROR_MESSAGE_PREFIX L"vl::presentation::RunIOCommandOnNativeWindow(...)#"
			CHECK_ERROR(state, ERROR_MESSAGE_PREFIX L"IO command state is missing.");
			CHECK_ERROR(nativeController, ERROR_MESSAGE_PREFIX L"Native controller is missing.");

			auto targetWindow = nativeWindow;
			if (!targetWindow)
			{
				targetWindow = nativeController->WindowService()->GetMainWindow();
			}
			if (!targetWindow)
			{
				return WString::Unmanaged(iocommands::IO_COMMAND_SYNTAX);
			}

			auto ioCommand = iocommands::ParseIOCommand(nativeController, command);
			if (ioCommand.TryGet<iocommands::SyntaxErrorCommand>())
			{
				return WString::Unmanaged(iocommands::IO_COMMAND_SYNTAX);
			}

			iocommands::ExecuteIOCommand(state, nativeController, targetWindow, listeners, std::move(ioCommand));
			return WString::Unmanaged(L"Queued");
#undef ERROR_MESSAGE_PREFIX
		}
	}
}


/***********************************************************************
.\UTILITIES\SHAREDSERVICES\GUISHAREDAUTOMATIONSERVICE_CONTROLS.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{
		using namespace collections;
		using namespace controls;
		using namespace compositions;
		using namespace elements;
		using namespace glr::xml;
		using namespace remoteprotocol;
		using namespace stream;

/***********************************************************************
AutomationService
***********************************************************************/

		WString AutomationService::DumpControlTreeInternal()
		{
			auto app = GetApplication();
			auto mainWindow = app->GetMainWindow();

			auto dumpRoot = Ptr(new glr::json::JsonObject);
			ConvertCustomTypeToJsonField(dumpRoot, L"WindowManagement", WString::Unmanaged(L"MultiWindow"));
			{
				auto field = Ptr(new glr::json::JsonObjectField);
				dumpRoot->fields.Add(field);
				field->name.value = L"MainWindow";
				field->value = DumpWindowClientArea(mainWindow, GetNativeWindowId(mainWindow->GetNativeWindow()), { 0,0 });
			}
			{
				auto field = Ptr(new glr::json::JsonObjectField);
				dumpRoot->fields.Add(field);
				field->name.value = L"SubWindows";

				auto subWindows = Ptr(new glr::json::JsonArray);
				field->value = subWindows;

				for (auto subWindow : app->windows)
				{
					if (subWindow != mainWindow && subWindow->GetVisible() && !dynamic_cast<GuiPopup*>(subWindow))
					{
						subWindows->items.Add(DumpWindowClientArea(subWindow, GetNativeWindowId(subWindow->GetNativeWindow()), { 0,0 }));
					}
				}
			}
			{
				auto field = Ptr(new glr::json::JsonObjectField);
				dumpRoot->fields.Add(field);
				field->name.value = L"Popups";

				auto popups = Ptr(new glr::json::JsonArray);
				field->value = popups;

				for (auto popup : app->openingPopups)
				{
					popups->items.Add(DumpWindowClientArea(popup, GetNativeWindowId(popup->GetNativeWindow()), { 0,0 }));
				}
			}
			return DumpJsonToString(dumpRoot);
		}

		AutomationService::AutomationService()
		{
		}

		AutomationService::~AutomationService()
		{
		}

		bool AutomationService::CanDumpControlTree()
		{
			return true;
		}

/***********************************************************************
AutomationServiceHosted
***********************************************************************/

		Nullable<WString> AutomationServiceHosted::GetNativeWindowId(INativeWindow* window)
		{
			return {};
		}

		INativeWindow* AutomationServiceHosted::GetNativeWindow(Nullable<WString> windowId)
		{
			return GetHostedApplication()->GetNativeWindowHost();
		}

		WString AutomationServiceHosted::DumpControlTreeInternal()
		{
			auto app = GetApplication();
			auto mainWindow = app->GetMainWindow();

			auto dumpRoot = Ptr(new glr::json::JsonObject);
			ConvertCustomTypeToJsonField(dumpRoot, L"WindowManagement", windowManagement);
			{
				auto field = Ptr(new glr::json::JsonObjectField);
				dumpRoot->fields.Add(field);
				field->name.value = L"MainWindow";
				field->value = DumpWindowClientArea(mainWindow, {}, { 0,0 });
				{
					auto subWindowsField = Ptr(new glr::json::JsonObjectField);
					field->value.Cast<glr::json::JsonObject>()->fields.Add(subWindowsField);
					subWindowsField->name.value = L"subWindowsInZOrder";

					auto subWindows = Ptr(new glr::json::JsonArray);
					subWindowsField->value = subWindows;

					auto hostedController = static_cast<GuiHostedController*>(GetHostedApplication());
					for (auto wmWindow : From(hostedController->wmManager->topMostedWindowsInOrder).Concat(hostedController->wmManager->ordinaryWindowsInOrder).Reverse())
					{
						if (wmWindow->id == mainWindow->GetNativeWindow()) continue;
						auto subWindow = app->windowMap[wmWindow->id];
						auto offset = mainWindow->GetNativeWindow()->Convert(wmWindow->bounds.LeftTop());
						subWindows->items.Add(DumpWindowClientArea(subWindow, {}, offset));
					}
				}
			}
			return DumpJsonToString(dumpRoot);
		}

		AutomationServiceHosted::AutomationServiceHosted()
		{
		}

		AutomationServiceHosted::~AutomationServiceHosted()
		{
		}

		bool AutomationServiceHosted::CanDumpControlTree()
		{
			return true;
		}

/***********************************************************************
RemoteProtocolAutomationService
***********************************************************************/

		WString RemoteProtocolAutomationService::RunIOCommandInternal(Nullable<WString> windowId, const WString& ioCommand)
		{
			auto window = dynamic_cast<GuiRemoteWindow*>(this->GetNativeWindow(windowId));
			if (!window)
			{
				return L"!Invalid window.";
			}

			return RunIOCommandOnNativeWindow(&ioCommandState, GetHostedApplication()->GetNativeController(), window, window->listeners, ioCommand);
		}

		RemoteProtocolAutomationService::RemoteProtocolAutomationService()
		{
			windowManagement = WString::Unmanaged(L"HostedRemoteProtocol");
		}

		RemoteProtocolAutomationService::~RemoteProtocolAutomationService()
		{
		}

		INativeAutomationService::IOCommandAvailability RemoteProtocolAutomationService::CanRunIOCommands()
		{
			return INativeAutomationService::IOCommandAvailability::Enabled;
		}

/***********************************************************************
DumpWindowClientArea
***********************************************************************/

		WString PrintControlThemeName(theme::ThemeName theme)
		{
			switch (theme)
			{
			case theme::ThemeName::Window: return WString::Unmanaged(L"Window");
#define GUI_DEFINE_THEME_NAME(TEMPLATE, CONTROL) case theme::ThemeName::CONTROL: return WString::Unmanaged(L ## #CONTROL);
				GUI_CONTROL_TEMPLATE_TYPES(GUI_DEFINE_THEME_NAME)
#undef GUI_DEFINE_THEME_NAME
			default: return WString::Unmanaged(L"Unknown");
			}
		}

		void AddJsonField(Ptr<glr::json::JsonObject> dump, const WString& name, Ptr<glr::json::JsonNode> value)
		{
			auto field = Ptr(new glr::json::JsonObjectField);
			dump->fields.Add(field);
			field->name.value = name;
			field->value = value;
		}

		Rect OffsetRect(Rect bounds, Point offset)
		{
			bounds.Move(offset.x, offset.y);
			return bounds;
		}

		WString HexByte(unsigned char value)
		{
			const wchar_t* code = L"0123456789ABCDEF";
			return WString::FromChar(code[value / 16]) + WString::FromChar(code[value % 16]);
		}

		WString PrintColor(Color color)
		{
			return WString::Unmanaged(L"#") + HexByte(color.r) + HexByte(color.g) + HexByte(color.b) + HexByte(color.a);
		}

		WString PrintElementShape(ElementShape shape)
		{
			switch (shape.shapeType)
			{
			case ElementShapeType::Rectangle:
				return WString::Unmanaged(L"Rectangle");
			case ElementShapeType::Ellipse:
				return WString::Unmanaged(L"Ellipse");
			case ElementShapeType::RoundRect:
				return L"RoundRect(" + itow(shape.radiusX) + L"," + itow(shape.radiusY) + L")";
			default:
				return WString::Unmanaged(L"Unknown");
			}
		}

		WString PrintSplitterDirection(Gui3DSplitterElement::Direction direction)
		{
			switch (direction)
			{
			case Gui3DSplitterElement::Horizontal:
				return WString::Unmanaged(L"Horizontal");
			case Gui3DSplitterElement::Vertical:
				return WString::Unmanaged(L"Vertical");
			default:
				return WString::Unmanaged(L"Unknown");
			}
		}

		WString PrintGradientDirection(GuiGradientBackgroundElement::Direction direction)
		{
			switch (direction)
			{
			case GuiGradientBackgroundElement::Horizontal:
				return WString::Unmanaged(L"Horizontal");
			case GuiGradientBackgroundElement::Vertical:
				return WString::Unmanaged(L"Vertical");
			case GuiGradientBackgroundElement::Slash:
				return WString::Unmanaged(L"Slash");
			case GuiGradientBackgroundElement::Backslash:
				return WString::Unmanaged(L"Backslash");
			default:
				return WString::Unmanaged(L"Unknown");
			}
		}

		WString PrintTextPos(TextPos position)
		{
			return L"(" + itow(position.row) + L"," + itow(position.column) + L")";
		}

		WString PrintFontStyle(const FontProperties& fontProperties)
		{
			return fontProperties.fontFamily + L"," + itow(fontProperties.size);
		}

		WString PrintLayout(GuiGraphicsComposition* composition)
		{
			if (auto table = dynamic_cast<GuiTableComposition*>(composition))
			{
				return L"Table:" + itow(table->GetRows()) + L"*" + itow(table->GetColumns());
			}
			else if (auto cell = dynamic_cast<GuiCellComposition*>(composition))
			{
				if (dynamic_cast<GuiTableComposition*>(cell->GetParent()))
				{
					return L"Cell:(" + itow(cell->GetRow()) + L"," + itow(cell->GetColumn()) + L")*(" + itow(cell->GetRowSpan()) + L"," + itow(cell->GetColumnSpan()) + L")";
				}
			}
			else if (auto rowSplitter = dynamic_cast<GuiRowSplitterComposition*>(composition))
			{
				return L"RowSplitter:" + itow(rowSplitter->GetRowsToTheTop());
			}
			else if (auto columnSplitter = dynamic_cast<GuiColumnSplitterComposition*>(composition))
			{
				return L"ColumnSplitter:" + itow(columnSplitter->GetColumnsToTheLeft());
			}
			else if (dynamic_cast<GuiStackComposition*>(composition))
			{
				return WString::Unmanaged(L"Stack");
			}
			else if (auto stackItem = dynamic_cast<GuiStackItemComposition*>(composition))
			{
				if (auto stack = dynamic_cast<GuiStackComposition*>(stackItem->GetParent()))
				{
					auto index = stack->GetStackItems().IndexOf(stackItem);
					if (index != -1)
					{
						return L"StackItem:" + itow(index);
					}
				}
			}
			else if (dynamic_cast<GuiFlowComposition*>(composition))
			{
				return WString::Unmanaged(L"Flow");
			}
			else if (auto flowItem = dynamic_cast<GuiFlowItemComposition*>(composition))
			{
				if (auto flow = dynamic_cast<GuiFlowComposition*>(flowItem->GetParent()))
				{
					auto index = flow->GetFlowItems().IndexOf(flowItem);
					if (index != -1)
					{
						return L"FlowItem:" + itow(index);
					}
				}
			}
			return WString::Empty;
		}

		WString PrintCursor(INativeCursor* cursor)
		{
			if (!cursor) return WString::Empty;
			if (!cursor->IsSystemCursor()) return WString::Unmanaged(L"Custom");

			switch (cursor->GetSystemCursorType())
			{
			case INativeCursor::SmallWaiting: return WString::Unmanaged(L"SmallWaiting");
			case INativeCursor::LargeWaiting: return WString::Unmanaged(L"LargeWaiting");
			case INativeCursor::Arrow: return WString::Unmanaged(L"Arrow");
			case INativeCursor::Cross: return WString::Unmanaged(L"Cross");
			case INativeCursor::Hand: return WString::Unmanaged(L"Hand");
			case INativeCursor::Help: return WString::Unmanaged(L"Help");
			case INativeCursor::IBeam: return WString::Unmanaged(L"IBeam");
			case INativeCursor::SizeAll: return WString::Unmanaged(L"SizeAll");
			case INativeCursor::SizeNESW: return WString::Unmanaged(L"SizeNESW");
			case INativeCursor::SizeNS: return WString::Unmanaged(L"SizeNS");
			case INativeCursor::SizeNWSE: return WString::Unmanaged(L"SizeNWSE");
			case INativeCursor::SizeWE: return WString::Unmanaged(L"SizeWE");
			default: return WString::Unmanaged(L"Unknown");
			}
		}

		WString PrintDocument(Ptr<DocumentModel> document)
		{
			if (!document) return WString::Empty;
			return GenerateToStream([&](StreamWriter& writer)
			{
				XmlPrint(document->SaveToXml(), writer);
			});
		}

		void DumpElement(Ptr<IGuiGraphicsElement> element, Ptr<glr::json::JsonObject> compositionDump)
		{
			if (!element) return;
			auto rawElement = element.Obj();
			WString elementDescription;

			if (dynamic_cast<GuiFocusRectangleElement*>(rawElement))
			{
				elementDescription = WString::Unmanaged(L"FocusRectangle");
			}
			else if (auto border = dynamic_cast<GuiSolidBorderElement*>(rawElement))
			{
				elementDescription = L"Border:" + PrintColor(border->GetColor()) + L"," + PrintElementShape(border->GetShape());
			}
			else if (auto border3D = dynamic_cast<Gui3DBorderElement*>(rawElement))
			{
				elementDescription = L"3DBorder:" + PrintColor(border3D->GetColor1()) + L"," + PrintColor(border3D->GetColor2());
			}
			else if (auto splitter3D = dynamic_cast<Gui3DSplitterElement*>(rawElement))
			{
				elementDescription = L"3DSplitter:" + PrintColor(splitter3D->GetColor1()) + L"," + PrintColor(splitter3D->GetColor2()) + L"," + PrintSplitterDirection(splitter3D->GetDirection());
			}
			else if (auto background = dynamic_cast<GuiSolidBackgroundElement*>(rawElement))
			{
				elementDescription = L"Background:" + PrintColor(background->GetColor()) + L"," + PrintElementShape(background->GetShape());
			}
			else if (auto gradient = dynamic_cast<GuiGradientBackgroundElement*>(rawElement))
			{
				elementDescription = L"Gradient:" + PrintColor(gradient->GetColor1()) + L"," + PrintColor(gradient->GetColor2()) + L"," + PrintGradientDirection(gradient->GetDirection()) + L"," + PrintElementShape(gradient->GetShape());
			}
			else if (auto shadow = dynamic_cast<GuiInnerShadowElement*>(rawElement))
			{
				elementDescription = L"InnerShadow:" + PrintColor(shadow->GetColor()) + L"," + itow(shadow->GetThickness());
			}
			else if (auto label = dynamic_cast<GuiSolidLabelElement*>(rawElement))
			{
				elementDescription = L"Label:" + PrintColor(label->GetColor()) + L"," + PrintFontStyle(label->GetFont());
				if (label->GetWrapLine()) elementDescription += L",WrapLine";
				if (label->GetEllipse()) elementDescription += L",Ellipse";
				if (label->GetMultiline()) elementDescription += L",Multiline";
				ConvertCustomTypeToJsonField(compositionDump, L"elementText", label->GetText());
			}
			else if (dynamic_cast<GuiImageFrameElement*>(rawElement))
			{
				elementDescription = WString::Unmanaged(L"Image");
			}
			else if (dynamic_cast<GuiPolygonElement*>(rawElement))
			{
				elementDescription = WString::Unmanaged(L"Polygon");
			}
			else if (auto document = dynamic_cast<GuiDocumentElement*>(rawElement))
			{
				elementDescription = L"Document:Selection" + PrintTextPos(document->GetCaretBegin()) + L"-" + PrintTextPos(document->GetCaretEnd());
				if (auto passwordChar = document->GetPasswordChar())
				{
					elementDescription += L",PasswordChar=" + WString::FromChar(passwordChar);
				}
				if (document->GetWrapLine())
				{
					elementDescription += L",WrapLine";
				}
				ConvertCustomTypeToJsonField(compositionDump, L"elementDocument", PrintDocument(document->GetDocument()));
			}

			if (elementDescription != WString::Empty)
			{
				ConvertCustomTypeToJsonField(compositionDump, L"element", elementDescription);
			}
		}

		Ptr<glr::json::JsonNode> DumpComposition(GuiGraphicsComposition* composition, Point offset)
		{
			auto compositionDump = Ptr(new glr::json::JsonObject);
			ConvertCustomTypeToJsonField(compositionDump, L"bounds", OffsetRect(composition->GetGlobalBounds(), offset));

			auto layout = PrintLayout(composition);
			if (layout != WString::Empty)
			{
				ConvertCustomTypeToJsonField(compositionDump, L"layout", layout);
			}

			auto cursor = PrintCursor(composition->GetAssociatedCursor());
			if (cursor != WString::Empty)
			{
				ConvertCustomTypeToJsonField(compositionDump, L"cursor", cursor);
			}

			DumpElement(composition->GetOwnedElement(), compositionDump);

			if (auto control = composition->GetAssociatedControl())
			{
				ConvertCustomTypeToJsonField(compositionDump, L"control", PrintControlThemeName(control->GetControlThemeName()));
			}

			if (composition->Children().Count() > 0)
			{
				auto children = Ptr(new glr::json::JsonArray);
				for (auto child : composition->Children())
				{
					if (child->GetEventuallyVisible())
					{
						children->items.Add(DumpComposition(child, offset));
					}
				}
				if (children->items.Count() > 0)
				{
					AddJsonField(compositionDump, L"children", children);
				}
			}

			return compositionDump;
		}

		Ptr<glr::json::JsonNode> DumpWindowClientArea(controls::GuiWindow* window, Nullable<WString> windowId, Point offset)
		{
			auto windowDump = Ptr(new glr::json::JsonObject);
			ConvertCustomTypeToJsonField(windowDump, L"title", window->GetText());
			if (windowId)
			{
				ConvertCustomTypeToJsonField(windowDump, L"windowId", windowId.Value());
			}

			{
				Size size = window->GetBoundsComposition()->GetCachedBounds().GetSize();
				ConvertCustomTypeToJsonField(windowDump, L"bounds", Rect(offset, size));
			}
			AddJsonField(windowDump, L"composition", DumpComposition(window->GetBoundsComposition(), offset));
			return windowDump;
		}
	}
}


/***********************************************************************
.\UTILITIES\SHAREDSERVICES\GUISHAREDCALLBACKSERVICE.CPP
***********************************************************************/

namespace vl
{
	namespace presentation
	{

/***********************************************************************
SharedCallbackService
***********************************************************************/

		SharedCallbackService::SharedCallbackService()
		{
		}

		SharedCallbackService::~SharedCallbackService()
		{
		}

		bool SharedCallbackService::InstallListener(INativeControllerListener* listener)
		{
			if(listeners.Contains(listener))
			{
				return false;
			}
			else
			{
				listeners.Add(listener);
				return true;
			}
		}

		bool SharedCallbackService::UninstallListener(INativeControllerListener* listener)
		{
			if(listeners.Contains(listener))
			{
				listeners.Remove(listener);
				return true;
			}
			else
			{
				return false;
			}
		}

		INativeCallbackInvoker* SharedCallbackService::Invoker()
		{
			return this;
		}

		void SharedCallbackService::InvokeGlobalTimer()
		{
			// TODO: (enumerable) foreach
			for(vint i=0;i<listeners.Count();i++)
			{
				listeners[i]->GlobalTimer();
			}
		}

		void SharedCallbackService::InvokeClipboardUpdated()
		{
			// TODO: (enumerable) foreach
			for(vint i=0;i<listeners.Count();i++)
			{
				listeners[i]->ClipboardUpdated();
			}
		}

		void SharedCallbackService::InvokeGlobalShortcutKeyActivated(vint id)
		{
			// TODO: (enumerable) foreach
			for (vint i = 0; i < listeners.Count(); i++)
			{
				listeners[i]->GlobalShortcutKeyActivated(id);
			}
		}

		void SharedCallbackService::InvokeNativeWindowCreated(INativeWindow* window)
		{
			// TODO: (enumerable) foreach
			for(vint i=0;i<listeners.Count();i++)
			{
				listeners[i]->NativeWindowCreated(window);
			}
		}

		void SharedCallbackService::InvokeNativeWindowDestroying(INativeWindow* window)
		{
			// TODO: (enumerable) foreach
			for(vint i=0;i<listeners.Count();i++)
			{
				listeners[i]->NativeWindowDestroying(window);
			}
		}

		void SharedCallbackService::InvokeEnvironmentChanged()
		{
			// TODO: (enumerable) foreach
			for(vint i=0;i<listeners.Count();i++)
			{
				listeners[i]->EnvironmentChanged();
			}
		}
	}
}
