diff --git a/src/BetterControls.Design.Client/BetterControls.Design.Client.csproj b/src/BetterControls.Design.Client/BetterControls.Design.Client.csproj
new file mode 100644
index 0000000..4b7be70
--- /dev/null
+++ b/src/BetterControls.Design.Client/BetterControls.Design.Client.csproj
@@ -0,0 +1,21 @@
+
+
+
+ net472
+ true
+ 9.0
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/BetterControls.Design.Client/BetterToolbarTypeRoutingProvider.cs b/src/BetterControls.Design.Client/BetterToolbarTypeRoutingProvider.cs
new file mode 100644
index 0000000..8d1d7b2
--- /dev/null
+++ b/src/BetterControls.Design.Client/BetterToolbarTypeRoutingProvider.cs
@@ -0,0 +1,45 @@
+using BetterControls.Design.Protocol;
+using Microsoft.DotNet.DesignTools.Client.TypeRouting;
+using System.Collections.Generic;
+
+namespace BetterControls.Design
+{
+ ///
+ /// Represents the toolbar type routing provider.
+ ///
+ [ExportTypeRoutingDefinitionProvider]
+ internal class BetterToolbarTypeRoutingProvider : TypeRoutingDefinitionProvider
+ {
+ ///
+ /// Initialize a new instance of .
+ ///
+ public BetterToolbarTypeRoutingProvider() { }
+
+ ///
+ ///
+ ///
+ ///
+ public override IEnumerable GetDefinitions()
+ {
+ return new[]
+ {
+ new TypeRoutingDefinition(
+ TypeRoutingKinds.Editor,
+ nameof(EditorNames.BetterToolbarItemCollectionEditor),
+ typeof(BetterToolbarItemCollectionEditor)),
+ new TypeRoutingDefinition(
+ TypeRoutingKinds.Editor,
+ nameof(EditorNames.BetterMenuBarItemCollectionEditor),
+ typeof(BetterMenuBarItemCollectionEditor)),
+ new TypeRoutingDefinition(
+ TypeRoutingKinds.Editor,
+ nameof(EditorNames.BetterMenuItemCollectionEditor),
+ typeof(BetterMenuItemCollectionEditor)),
+ new TypeRoutingDefinition(
+ TypeRoutingKinds.Editor,
+ nameof(EditorNames.ImageIndexEditor),
+ typeof(ImageIndexEditor)),
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/BetterControls.Design.Client/Editors/BetterCollectionEditor.cs b/src/BetterControls.Design.Client/Editors/BetterCollectionEditor.cs
new file mode 100644
index 0000000..094d269
--- /dev/null
+++ b/src/BetterControls.Design.Client/Editors/BetterCollectionEditor.cs
@@ -0,0 +1,19 @@
+using Microsoft.DotNet.DesignTools.Client.Editors;
+using System;
+
+namespace BetterControls.Design
+{
+ ///
+ /// Extend this class to create a collection editor.
+ ///
+ public abstract class BetterCollectionEditor : CollectionEditor
+ {
+ ///
+ /// Initialize a new instance of .
+ ///
+ /// The type that this collection editor is associated with.
+ public BetterCollectionEditor(Type collectionType)
+ : base(collectionType)
+ { }
+ }
+}
\ No newline at end of file
diff --git a/src/BetterControls.Design.ClientServerProtocol/BetterControls.Design.ClientServerProtocol.csproj b/src/BetterControls.Design.ClientServerProtocol/BetterControls.Design.ClientServerProtocol.csproj
new file mode 100644
index 0000000..e2092aa
--- /dev/null
+++ b/src/BetterControls.Design.ClientServerProtocol/BetterControls.Design.ClientServerProtocol.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net6.0-windows;net472
+ disable
+ enable
+ 9.0
+
+
+
+
+
+
diff --git a/src/BetterControls.Design.ClientServerProtocol/CollectionEditorNames.cs b/src/BetterControls.Design.ClientServerProtocol/CollectionEditorNames.cs
new file mode 100644
index 0000000..99f6757
--- /dev/null
+++ b/src/BetterControls.Design.ClientServerProtocol/CollectionEditorNames.cs
@@ -0,0 +1,9 @@
+namespace WinForms.Tiles.ClientServerProtocol
+{
+ public static class CollectionEditorNames
+ {
+ public const string BetterToolbarItemCollectionEditor = nameof(BetterToolbarItemCollectionEditor);
+ public const string BetterMenuBarItemCollectionEditor = nameof(BetterMenuBarItemCollectionEditor);
+ public const string BetterMenuItemCollectionEditor = nameof(BetterMenuItemCollectionEditor);
+ }
+}
\ No newline at end of file
diff --git a/src/BetterControls.Design.ClientServerProtocol/EditorNames.cs b/src/BetterControls.Design.ClientServerProtocol/EditorNames.cs
new file mode 100644
index 0000000..0808e94
--- /dev/null
+++ b/src/BetterControls.Design.ClientServerProtocol/EditorNames.cs
@@ -0,0 +1,10 @@
+namespace BetterControls.Design.Protocol
+{
+ public static class EditorNames
+ {
+ public const string BetterToolbarItemCollectionEditor = nameof(BetterToolbarItemCollectionEditor);
+ public const string BetterMenuBarItemCollectionEditor = nameof(BetterMenuBarItemCollectionEditor);
+ public const string BetterMenuItemCollectionEditor = nameof(BetterMenuItemCollectionEditor);
+ public const string ImageIndexEditor = nameof(ImageIndexEditor);
+ }
+}
\ No newline at end of file
diff --git a/src/BetterControls.Design.Server/BetterControls.Design.Server.csproj b/src/BetterControls.Design.Server/BetterControls.Design.Server.csproj
new file mode 100644
index 0000000..7e5248e
--- /dev/null
+++ b/src/BetterControls.Design.Server/BetterControls.Design.Server.csproj
@@ -0,0 +1,21 @@
+
+
+
+ net6.0-windows
+ true
+ disable
+ disable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BetterControls.Design.Server/BetterToolbarTypeRoutingProvider.cs b/src/BetterControls.Design.Server/BetterToolbarTypeRoutingProvider.cs
new file mode 100644
index 0000000..bc012e2
--- /dev/null
+++ b/src/BetterControls.Design.Server/BetterToolbarTypeRoutingProvider.cs
@@ -0,0 +1,42 @@
+using Microsoft.DotNet.DesignTools.TypeRouting;
+using System.Collections.Generic;
+
+namespace BetterControls.Design
+{
+ ///
+ /// Represents the toolbar type routing provider.
+ ///
+ [ExportTypeRoutingDefinitionProvider]
+ internal class BetterToolbarTypeRoutingProvider : TypeRoutingDefinitionProvider
+ {
+ ///
+ /// Initialize a new instance of .
+ ///
+ public BetterToolbarTypeRoutingProvider() { }
+
+ ///
+ ///
+ ///
+ ///
+ public override IEnumerable GetDefinitions()
+ => new[]
+ {
+ new TypeRoutingDefinition(
+ TypeRoutingKinds.Designer,
+ nameof(BetterToolbarDesigner),
+ typeof(BetterToolbarDesigner)),
+ new TypeRoutingDefinition(
+ TypeRoutingKinds.Designer,
+ nameof(BetterToolbarItemDesigner),
+ typeof(BetterToolbarItemDesigner)),
+ new TypeRoutingDefinition(
+ TypeRoutingKinds.Designer,
+ nameof(BetterToolbarButtonDesigner),
+ typeof(BetterToolbarButtonDesigner)),
+ new TypeRoutingDefinition(
+ TypeRoutingKinds.Designer,
+ nameof(BetterMenuBarDesigner),
+ typeof(BetterMenuBarDesigner))
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/BetterControls.Design.Server/Designers/BetterComponentDesigner.cs b/src/BetterControls.Design.Server/Designers/BetterComponentDesigner.cs
new file mode 100644
index 0000000..7f281a8
--- /dev/null
+++ b/src/BetterControls.Design.Server/Designers/BetterComponentDesigner.cs
@@ -0,0 +1,36 @@
+using Microsoft.DotNet.DesignTools.Designers;
+using System.ComponentModel.Design;
+
+namespace BetterControls.Design
+{
+ ///
+ /// Extend this class to create a component designer.
+ ///
+ public abstract class BetterComponentDesigner : ComponentDesigner
+ {
+ ///
+ /// Initialize a new instance of .
+ ///
+ public BetterComponentDesigner() { }
+
+ #region Private Member Fields
+
+ private IDesignerHost _designerHost;
+
+ #endregion
+
+ ///
+ /// Gets the designer host associated with this component.
+ ///
+ protected IDesignerHost DesignerHost
+ {
+ get
+ {
+ if (_designerHost is null)
+ _designerHost = GetService();
+
+ return _designerHost;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/BetterControls.Design.Server/Designers/BetterControlActionList.cs b/src/BetterControls.Design.Server/Designers/BetterControlActionList.cs
new file mode 100644
index 0000000..e39c591
--- /dev/null
+++ b/src/BetterControls.Design.Server/Designers/BetterControlActionList.cs
@@ -0,0 +1,48 @@
+using Microsoft.DotNet.DesignTools.Designers;
+using Microsoft.DotNet.DesignTools.Designers.Actions;
+using System;
+using System.ComponentModel.Design;
+
+namespace BetterControls.Design
+{
+ ///
+ /// Extend from this class to indicate that the implementing class is an action list.
+ ///
+ internal class BetterControlActionList : DesignerActionList
+ {
+ ///
+ /// Initialize a new instance of .
+ ///
+ /// The designer that is associated with this action list.
+ internal BetterControlActionList(Microsoft.DotNet.DesignTools.Designers.ControlDesigner designer)
+ : base(designer.Component)
+ {
+ Designer = designer ?? throw new ArgumentNullException(nameof(designer));
+ }
+
+ #region Private Member Fields
+
+ private IDesignerHost _designerHost;
+
+ #endregion
+
+ ///
+ /// Gets the designer that is associated with this action list.
+ ///
+ protected Microsoft.DotNet.DesignTools.Designers.ControlDesigner Designer { get; }
+
+ ///
+ /// Gets the designer host associated with this component.
+ ///
+ protected IDesignerHost DesignerHost
+ {
+ get
+ {
+ if(_designerHost is null)
+ _designerHost = GetService();
+
+ return _designerHost;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/BetterControls.Design.Server/Designers/BetterControlDesigner.cs b/src/BetterControls.Design.Server/Designers/BetterControlDesigner.cs
new file mode 100644
index 0000000..0de3593
--- /dev/null
+++ b/src/BetterControls.Design.Server/Designers/BetterControlDesigner.cs
@@ -0,0 +1,36 @@
+using Microsoft.DotNet.DesignTools.Designers;
+using System.ComponentModel.Design;
+
+namespace BetterControls.Design
+{
+ ///
+ /// Extend this class to create a control designer.
+ ///
+ public abstract class BetterControlDesigner : ControlDesigner
+ {
+ ///
+ /// Initialize a new instance of .
+ ///
+ public BetterControlDesigner() { }
+
+ #region Private Member Fields
+
+ private IDesignerHost _designerHost;
+
+ #endregion
+
+ ///
+ /// Gets the designer host associated with this component.
+ ///
+ protected IDesignerHost DesignerHost
+ {
+ get
+ {
+ if (_designerHost is null)
+ _designerHost = GetService();
+
+ return _designerHost;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/BetterControls.Design.Server/Designers/BetterToolbarButtonDesigner.cs b/src/BetterControls.Design.Server/Designers/BetterToolbarButtonDesigner.cs
new file mode 100644
index 0000000..fa770ec
--- /dev/null
+++ b/src/BetterControls.Design.Server/Designers/BetterToolbarButtonDesigner.cs
@@ -0,0 +1,37 @@
+using System.Collections;
+using System.ComponentModel;
+
+namespace BetterControls.Design
+{
+ ///
+ /// Designer for .
+ ///
+ internal class BetterToolbarButtonDesigner : BetterToolbarItemDesigner
+ {
+ ///
+ /// Initialize a new instance of .
+ ///
+ public BetterToolbarButtonDesigner() { }
+
+ ///
+ ///
+ ///
+ ///
+ public override void InitializeNewComponent(IDictionary defaultValues)
+ {
+ base.InitializeNewComponent(defaultValues);
+
+ PropertyDescriptor nameProperty = TypeDescriptor.GetProperties(Component)["Name"];
+ if (nameProperty != null && nameProperty.PropertyType == typeof(string))
+ {
+ string itemText = (string)nameProperty.GetValue(Component);
+
+ PropertyDescriptor textProperty = TypeDescriptor.GetProperties(Component)["Text"];
+ if (textProperty != null)
+ {
+ textProperty.SetValue(Component, itemText);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/BetterControls.Design.Server/Designers/BetterToolbarDesigner.ActionList.cs b/src/BetterControls.Design.Server/Designers/BetterToolbarDesigner.ActionList.cs
new file mode 100644
index 0000000..cdf03b7
--- /dev/null
+++ b/src/BetterControls.Design.Server/Designers/BetterToolbarDesigner.ActionList.cs
@@ -0,0 +1,208 @@
+using Microsoft.DotNet.DesignTools.Designers.Actions;
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.Windows.Forms;
+
+namespace BetterControls.Design
+{
+ ///
+ /// Designer for .
+ ///
+ internal partial class BetterToolbarDesigner
+ {
+ ///
+ ///
+ ///
+ public override DesignerActionListCollection ActionLists => new DesignerActionListCollection()
+ {
+ new ActionList(this)
+ };
+
+ ///
+ /// Adds a to the toolbar.
+ ///
+ protected void AddPushButton() => AddItem();
+
+ ///
+ /// Adds a to the toolbar.
+ ///
+ protected void AddToggleButton() => AddItem();
+
+ ///
+ /// Adds a to the toolbar.
+ ///
+ protected void AddDropDownButton() => AddItem();
+
+ ///
+ /// Adds a to the toolbar.
+ ///
+ protected void AddSeparator() => AddItem();
+
+ ///
+ /// Adds a new to the toolbar.
+ ///
+ /// The type of item to add extending from .
+ private protected void AddItem()
+ where TItemType : BetterToolbarItem
+ {
+ DesignerTransaction transaction = null;
+
+ try
+ {
+ transaction = DesignerHost.CreateTransaction("Inserting Item");
+
+ TItemType button = (TItemType)DesignerHost.CreateComponent(typeof(TItemType));
+
+ MemberDescriptor itemsMember = TypeDescriptor.GetProperties(Component!)[nameof(BetterToolbar.Items)];
+
+ RaiseComponentChanging(itemsMember);
+
+ PropertyDescriptor nameProperty = TypeDescriptor.GetProperties(button)["Name"];
+ if (nameProperty != null && nameProperty.PropertyType == typeof(string))
+ {
+ string itemText = (string)nameProperty.GetValue(button);
+
+ PropertyDescriptor textProperty = TypeDescriptor.GetProperties(button)["Text"];
+ if (textProperty != null)
+ {
+ textProperty.SetValue(button, itemText);
+ }
+ }
+
+ ((BetterToolbar)Component!).Items.Add(button);
+
+ RaiseComponentChanged(itemsMember);
+ }
+ finally
+ {
+ transaction?.Commit();
+ }
+
+ Refresh();
+ }
+
+ ///
+ /// Action list for .
+ ///
+ private class ActionList : BetterControlActionList
+ {
+ ///
+ /// Initialize a new instance of .
+ ///
+ /// The designer that is associated with this action list.
+ public ActionList(BetterToolbarDesigner designer)
+ : base(designer)
+ { }
+
+ ///
+ /// Invokes the property.
+ ///
+ public void InvokeItemsProperty() => Designer.InvokePropertyEditor("Items");
+
+ ///
+ /// Invokes the 'Add Push Button' action list item.
+ ///
+ public void InvokeAddPushButton() => ((BetterToolbarDesigner)Designer).AddPushButton();
+
+ ///
+ /// Invokes the 'Add Toggle Button' action list item.
+ ///
+ public void InvokeAddToggleButton() => ((BetterToolbarDesigner)Designer).AddToggleButton();
+
+ ///
+ /// Invokes the 'Add Drop-down Button' action list item.
+ ///
+ public void InvokeAddDropDownButton() => ((BetterToolbarDesigner)Designer).AddDropDownButton();
+
+ ///
+ /// Invokes the 'Add Separator' action list item.
+ ///
+ public void InvokeAddSeparator() => ((BetterToolbarDesigner)Designer).AddSeparator();
+
+ ///
+ /// Invokes the 'Dock in Parent Container'/'Undock in Parent Container' action list item.
+ ///
+ public void InvokeDock()
+ {
+ using DesignerTransaction transaction = DesignerHost.CreateTransaction();
+
+ PropertyDescriptor dockProperty = TypeDescriptor.GetProperties(Component)["Dock"];
+ DockStyle dock = (DockStyle)dockProperty.GetValue(Component);
+ if (dock != DockStyle.None)
+ {
+ dockProperty.SetValue(Component, DockStyle.None);
+ }
+ else
+ {
+ dockProperty.SetValue(Component, DockStyle.Top);
+ }
+
+ transaction.Commit();
+ }
+
+ ///
+ /// Gets the name of the dock action.
+ ///
+ /// The name of the dock action.
+ private string GetDockActionName()
+ {
+ PropertyDescriptor dockProperty = TypeDescriptor.GetProperties(Component)["Dock"];
+ if (dockProperty != null && dockProperty.PropertyType == typeof(DockStyle))
+ {
+ DockStyle dock = (DockStyle)dockProperty.GetValue(Component);
+ if (dock != DockStyle.None)
+ {
+ return "Undock in Parent Container";
+ }
+ else
+ {
+ return "Dock in Parent Container";
+ }
+ }
+ return null;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public override DesignerActionItemCollection GetSortedActionItems()
+ {
+ DesignerActionItemCollection actionItems = new DesignerActionItemCollection();
+
+ actionItems.Add(new DesignerActionMethodItem(
+ this,
+ nameof(InvokeDock),
+ GetDockActionName(),
+ false));
+ actionItems.Add(new DesignerActionMethodItem(
+ this,
+ nameof(InvokeItemsProperty),
+ "Edit Items...",
+ true));
+ actionItems.Add(new DesignerActionMethodItem(
+ this,
+ nameof(InvokeAddPushButton),
+ "Add Push Button",
+ true));
+ actionItems.Add(new DesignerActionMethodItem(
+ this,
+ nameof(InvokeAddToggleButton),
+ "Add Toggle Button",
+ true));
+ actionItems.Add(new DesignerActionMethodItem(
+ this,
+ nameof(InvokeAddDropDownButton),
+ "Add Drop-down Button",
+ true));
+ actionItems.Add(new DesignerActionMethodItem(
+ this,
+ nameof(InvokeAddSeparator),
+ "Add Separator",
+ true));
+
+ return actionItems;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/BetterControls.Design.Server/Designers/BetterToolbarDesigner.cs b/src/BetterControls.Design.Server/Designers/BetterToolbarDesigner.cs
new file mode 100644
index 0000000..6650dbb
--- /dev/null
+++ b/src/BetterControls.Design.Server/Designers/BetterToolbarDesigner.cs
@@ -0,0 +1,120 @@
+using Microsoft.DotNet.DesignTools.Designers;
+using Microsoft.DotNet.DesignTools.Designers.Actions;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Windows.Forms;
+
+namespace BetterControls.Design
+{
+ ///
+ /// Designer for .
+ ///
+ internal partial class BetterToolbarDesigner : BetterControlDesigner
+ {
+ ///
+ /// Initialize a new instance of .
+ ///
+ public BetterToolbarDesigner() { }
+
+ ///
+ ///
+ ///
+ public override SelectionRules SelectionRules
+ {
+ get
+ {
+ SelectionRules selectionRules = base.SelectionRules;
+
+ PropertyDescriptor dockProperty = TypeDescriptor.GetProperties(Component)["Dock"];
+ PropertyDescriptor autoSizeProperty = TypeDescriptor.GetProperties(Component)["AutoSize"];
+ if (dockProperty != null && autoSizeProperty != null)
+ {
+ DockStyle dock = (DockStyle)dockProperty.GetValue(Component);
+ bool autoSize = (bool)autoSizeProperty.GetValue(Component);
+ if (autoSize)
+ {
+ selectionRules &= ~(SelectionRules.TopSizeable | SelectionRules.BottomSizeable);
+ if (dock != DockStyle.None)
+ selectionRules &= ~SelectionRules.AllSizeable;
+ }
+ }
+
+ return selectionRules;
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public override void InitializeNewComponent(IDictionary defaultValues)
+ {
+ base.InitializeNewComponent(defaultValues);
+
+ PropertyDescriptor dockProperty = TypeDescriptor.GetProperties(Component)["Dock"];
+ if (dockProperty != null && dockProperty.PropertyType == typeof(DockStyle))
+ {
+ dockProperty.SetValue(Component, DockStyle.Top);
+ }
+ }
+
+ protected override void OnMouseDragEnd(bool cancel, Keys modifierKeys)
+ {
+ base.OnMouseDragEnd(cancel, modifierKeys);
+ }
+
+
+
+ ///
+ ///
+ ///
+ public override IReadOnlyCollection AssociatedComponents
+ {
+ get
+ {
+ if (Control is BetterToolbar toolbar)
+ {
+ List items = new List();
+
+ foreach (BetterToolbarItem item in toolbar.Items)
+ {
+ items.Add(item);
+
+ if (item is BetterToolbarDropDownButton button)
+ {
+ if (button.DropDownMenu != null)
+ {
+ foreach (BetterMenuItem menuItem in button.DropDownMenu.Items)
+ {
+ items.Add(menuItem);
+ }
+ }
+ }
+ }
+
+ return items.AsReadOnly();
+ }
+
+ return base.AssociatedComponents;
+ }
+ }
+
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ base.OnMouseUp(e);
+
+ ((BetterToolbar)Component).UpdateItemDimensions();
+ }
+
+
+
+ protected void Refresh()
+ {
+ DesignerActionUIService das = GetService();
+ das?.Refresh(Component!);
+ }
+ }
+}
diff --git a/src/BetterControls.Design.Server/Designers/BetterToolbarItemDesigner.cs b/src/BetterControls.Design.Server/Designers/BetterToolbarItemDesigner.cs
new file mode 100644
index 0000000..284ba23
--- /dev/null
+++ b/src/BetterControls.Design.Server/Designers/BetterToolbarItemDesigner.cs
@@ -0,0 +1,16 @@
+using System.Collections;
+using System.ComponentModel;
+
+namespace BetterControls.Design
+{
+ ///
+ /// Designer for .
+ ///
+ internal partial class BetterToolbarItemDesigner : BetterComponentDesigner
+ {
+ ///
+ /// Initialize a new instance of .
+ ///
+ public BetterToolbarItemDesigner() { }
+ }
+}
\ No newline at end of file
diff --git a/src/BetterControls.Design.Server/Editors/BetterCollectionEditor.cs b/src/BetterControls.Design.Server/Editors/BetterCollectionEditor.cs
new file mode 100644
index 0000000..f33a621
--- /dev/null
+++ b/src/BetterControls.Design.Server/Editors/BetterCollectionEditor.cs
@@ -0,0 +1,20 @@
+using Microsoft.DotNet.DesignTools.Editors;
+using System;
+
+namespace BetterControls.Design
+{
+ ///
+ /// Extend this class to create a collection editor.
+ ///
+ public abstract class BetterCollectionEditor : CollectionEditor
+ {
+ ///
+ /// Initialize a new instance of .
+ ///
+ /// The service provider as an instance of .
+ /// The type that this collection editor is associated with.
+ public BetterCollectionEditor(IServiceProvider services, Type collectionType)
+ : base(services, collectionType)
+ { }
+ }
+}
\ No newline at end of file