563 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			563 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections;
 | |
| using System.ComponentModel;
 | |
| using System.ComponentModel.Design;
 | |
| using System.Drawing;
 | |
| using System.Windows.Forms;
 | |
| using System.Windows.Forms.Design;
 | |
| using DevComponents.DotNetBar.Controls;
 | |
| 
 | |
| namespace DevComponents.DotNetBar.Design
 | |
| {
 | |
|     public class ToolboxControlDesigner : ControlDesigner
 | |
|     {
 | |
|         public void SelectionRefresh()
 | |
|         {
 | |
|             Message m = new Message();
 | |
|             m.Msg = 0x115;
 | |
|             base.WndProc(ref m);
 | |
|         }
 | |
| 
 | |
|         public override void Initialize(IComponent component)
 | |
|         {
 | |
|             base.Initialize(component);
 | |
| 
 | |
|             IDesignerHost dh = this.GetService(typeof(IDesignerHost)) as IDesignerHost;
 | |
|             if (dh != null)
 | |
|                 dh.LoadComplete += new EventHandler(dh_LoadComplete);
 | |
| 
 | |
|             // If our item is removed we need to clean-up
 | |
|             IComponentChangeService cc = (IComponentChangeService)GetService(typeof(IComponentChangeService));
 | |
|             if (cc != null)
 | |
|             {
 | |
|                 cc.ComponentRemoved += ComponentRemoved;
 | |
|                 cc.ComponentRemoving += ComponentRemoving;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private bool _InternalRemoving = false;
 | |
|         private void ComponentRemoving(object sender, ComponentEventArgs e)
 | |
|         {
 | |
|             if (e.Component != this.Component) return;
 | |
| 
 | |
|             if (!_InternalRemoving)
 | |
|             {
 | |
|                 _InternalRemoving = true;
 | |
|                 try
 | |
|                 {
 | |
|                     // Unhook events
 | |
|                     IComponentChangeService cc = (IComponentChangeService)GetService(typeof(IComponentChangeService));
 | |
|                     if (cc != null)
 | |
|                         cc.ComponentRemoving -= ComponentRemoving;
 | |
| 
 | |
|                     ToolboxControl tc = (ToolboxControl) this.Component;
 | |
|                     IDesignerHost dh = (IDesignerHost)GetService(typeof(IDesignerHost));
 | |
| 
 | |
|                     if (dh == null || tc == null)
 | |
|                         return;
 | |
| 
 | |
|                     for (int i = tc.Groups.Count - 1; i >= 0; i--)
 | |
|                     {
 | |
|                         BaseItem item = tc.Groups[i];
 | |
| 
 | |
|                         // Covers the undo case in designer
 | |
|                         if (item.Parent == tc.ItemsPanel.GetBaseItemContainer())
 | |
|                         {
 | |
|                             DestroySubItems(item, dh);
 | |
|                             dh.DestroyComponent(item);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 finally
 | |
|                 {
 | |
|                     _InternalRemoving = false;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected virtual void DestroySubItems(BaseItem parent, IDesignerHost dh)
 | |
|         {
 | |
|             if (parent is ControlContainerItem)
 | |
|             {
 | |
|                 if (((ControlContainerItem)parent).Control != null)
 | |
|                 {
 | |
|                     Control c = ((ControlContainerItem)parent).Control;
 | |
|                     ((ControlContainerItem)parent).Control = null;
 | |
|                     dh.DestroyComponent(c);
 | |
|                 }
 | |
|             }
 | |
|             else if (parent is DockContainerItem)
 | |
|             {
 | |
|                 if (((DockContainerItem)parent).Control != null)
 | |
|                 {
 | |
|                     Control c = ((DockContainerItem)parent).Control;
 | |
|                     ((DockContainerItem)parent).Control = null;
 | |
|                     dh.DestroyComponent(c);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             BaseItem[] subitems = new BaseItem[parent.SubItems.Count];
 | |
|             parent.SubItems.CopyTo(subitems, 0);
 | |
|             foreach (BaseItem item in subitems)
 | |
|             {
 | |
|                 DestroySubItems(item, dh);
 | |
|                 dh.DestroyComponent(item);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected virtual void DestroySubItems(BaseItem parent)
 | |
|         {
 | |
|             IDesignerHost dh = GetService(typeof(IDesignerHost)) as IDesignerHost;
 | |
|             if (dh != null)
 | |
|                 DestroySubItems(parent, dh);
 | |
|         }
 | |
| 
 | |
|         private void ComponentRemoved(object sender, ComponentEventArgs e)
 | |
|         {
 | |
|             ToolboxGroup group = e.Component as ToolboxGroup;
 | |
|             ToolboxControl tc = (ToolboxControl)this.Control;
 | |
|             if (group != null && tc != null)
 | |
|             {
 | |
|                 if (tc.Groups.Contains(group))
 | |
|                 {
 | |
|                     IComponentChangeService cc = (IComponentChangeService)GetService(typeof(IComponentChangeService));
 | |
|                     if (cc != null)
 | |
|                         cc.OnComponentChanging(tc, TypeDescriptor.GetProperties(tc)["Groups"]);
 | |
|                     tc.Groups.Remove(group);
 | |
|                     if (cc != null)
 | |
|                         cc.OnComponentChanged(tc, TypeDescriptor.GetProperties(tc)["Groups"], null, null);
 | |
|                 }
 | |
|                 this.RecalcLayout();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override System.Collections.ICollection AssociatedComponents
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 ArrayList c = new ArrayList(base.AssociatedComponents);
 | |
|                 ToolboxControl tc = (ToolboxControl) this.Control;
 | |
|                 if (tc != null)
 | |
|                 {
 | |
|                     foreach (BaseItem item in tc.Groups)
 | |
|                     {
 | |
|                         if (item.DesignMode)
 | |
|                             c.Add(item);
 | |
|                     }
 | |
|                 }
 | |
|                 return c;
 | |
|             }
 | |
|         }
 | |
|         private void RecalcLayout()
 | |
|         {
 | |
|             ToolboxControl tc = (ToolboxControl)this.Control;
 | |
|             if (tc == null) return;
 | |
|             tc.RecalcLayout();
 | |
|         }
 | |
| 
 | |
|         public override void InitializeNewComponent(IDictionary defaultValues)
 | |
|         {
 | |
|             SetDefaults();
 | |
|             base.InitializeNewComponent(defaultValues);
 | |
|         }
 | |
| 
 | |
|         private void SetDefaults()
 | |
|         {
 | |
|             ToolboxGroup group = CreateToolboxGroup(true);
 | |
|             CreateToolboxItem(group, true);
 | |
|             IDesignerHost dh = (IDesignerHost)GetService(typeof(IDesignerHost));
 | |
|             if (dh == null)
 | |
|                 return;
 | |
|             this.Control.Size = new Size(200, 200);
 | |
| #if !TRIAL
 | |
|             string key = GetLicenseKey();
 | |
|             ToolboxControl tc = this.Control as ToolboxControl;
 | |
|             tc.LicenseKey = key;
 | |
| #endif
 | |
|         }
 | |
| 
 | |
|         public void CreateGroup()
 | |
|         {
 | |
|             CreateToolboxGroup(true);
 | |
|         }
 | |
|         private ToolboxGroup CreateToolboxGroup(bool addToCollections)
 | |
|         {
 | |
|             ToolboxControl tc = this.Control as ToolboxControl;
 | |
| 
 | |
|             IDesignerHost dh = (IDesignerHost)GetService(typeof(IDesignerHost));
 | |
|             if (dh == null)
 | |
|                 return null;
 | |
| 
 | |
|             ToolboxGroup toolboxGroup = null;
 | |
| 
 | |
|             IComponentChangeService change = this.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
 | |
|             if (addToCollections)
 | |
|             {
 | |
|                 if (change != null)
 | |
|                 {
 | |
|                     change.OnComponentChanging(this.Component, TypeDescriptor.GetProperties(tc).Find("Groups", true));
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             toolboxGroup = dh.CreateComponent(typeof(ToolboxGroup)) as ToolboxGroup;
 | |
| 
 | |
|             if (toolboxGroup != null)
 | |
|             {
 | |
|                 toolboxGroup.TitleText = toolboxGroup.Name;
 | |
|                 toolboxGroup.Expanded = true;
 | |
|                 toolboxGroup.LayoutOrientation = eOrientation.Vertical;
 | |
|                 toolboxGroup.MultiLine = false;
 | |
|                 toolboxGroup.ResizeItemsToFit = true;
 | |
|                 if (addToCollections)
 | |
|                 {
 | |
|                     tc.Groups.Add(toolboxGroup);
 | |
| 
 | |
|                     if (change != null)
 | |
|                     {
 | |
|                         change.OnComponentChanged(this.Component, TypeDescriptor.GetProperties(tc).Find("Groups", true), null, null);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return toolboxGroup;
 | |
|         }
 | |
|         private ToolboxItem CreateToolboxItem(ToolboxGroup parentGroup, bool addToCollections)
 | |
|         {
 | |
|             ToolboxControl tc = this.Control as ToolboxControl;
 | |
| 
 | |
|             IDesignerHost dh = (IDesignerHost)GetService(typeof(IDesignerHost));
 | |
|             if (dh == null)
 | |
|                 return null;
 | |
| 
 | |
|             if (parentGroup == null)
 | |
|                 throw new ArgumentNullException("parentGroup", "ToolboxGroup must be specified");
 | |
| 
 | |
|             ToolboxItem item = null;
 | |
| 
 | |
|             IComponentChangeService change = this.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
 | |
|             if (addToCollections)
 | |
|             {
 | |
|                 if (change != null)
 | |
|                 {
 | |
|                     change.OnComponentChanging(this.Component, TypeDescriptor.GetProperties(parentGroup).Find("SubItems", true));
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             item = dh.CreateComponent(typeof(ToolboxItem)) as ToolboxItem;
 | |
| 
 | |
|             if (item != null)
 | |
|             {
 | |
|                 item.Text = item.Name;
 | |
|                 item.Symbol = "\ue251";
 | |
|                 item.SymbolSet = eSymbolSet.Material;
 | |
|                 if (addToCollections)
 | |
|                 {
 | |
|                     parentGroup.SubItems.Add(item);
 | |
| 
 | |
|                     if (change != null)
 | |
|                     {
 | |
|                         change.OnComponentChanged(this.Component, TypeDescriptor.GetProperties(parentGroup).Find("Nodes", true), null, null);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return item;
 | |
|         }
 | |
| 
 | |
|         protected override bool GetHitTest(System.Drawing.Point point)
 | |
|         {
 | |
|             if (base.GetHitTest(point))
 | |
|                 return true;
 | |
| 
 | |
|             ToolboxControl c = this.Control as ToolboxControl;
 | |
|             if (c == null) return false;
 | |
| 
 | |
|             Point pc = c.ItemsPanel.PointToClient(point);
 | |
|             if (c.ItemsPanel.VScrollBar != null && c.ItemsPanel.VScrollBar.Visible && c.ItemsPanel.VScrollBar.Bounds.Contains(pc))
 | |
|                 return true;
 | |
|             if (c.ItemsPanel.HScrollBar != null && c.ItemsPanel.HScrollBar.Visible && c.ItemsPanel.HScrollBar.Bounds.Contains(pc))
 | |
|                 return true;
 | |
| 
 | |
|             return base.GetHitTest(point);
 | |
|         }
 | |
| 
 | |
|         private bool IsControlSelected
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 ISelectionService ss = (ISelectionService)GetService(typeof(ISelectionService));
 | |
|                 if (ss == null) return false;
 | |
|                 ICollection selected = ss.GetSelectedComponents();
 | |
|                 if (IsSelected(selected, this.Control))
 | |
|                     return true;
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
|         private bool IsSelected(ICollection selectedComponents, object item)
 | |
|         {
 | |
|             foreach (object o in selectedComponents)
 | |
|             {
 | |
|                 if (o == item) return true;
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         private System.Windows.Forms.Control _DesignerHost = null;
 | |
|         /// <summary>
 | |
|         /// Selection support for items on container.
 | |
|         /// </summary>
 | |
|         protected override void WndProc(ref Message m)
 | |
|         {
 | |
|             if (_DesignerHost == null)
 | |
|                 _DesignerHost = System.Windows.Forms.Control.FromHandle(m.HWnd);
 | |
|             switch (m.Msg)
 | |
|             {
 | |
|                 case WinApi.WM_LBUTTONDOWN:
 | |
|                 case WinApi.WM_RBUTTONDOWN:
 | |
|                     {
 | |
|                         if (OnMouseDown(ref m, m.Msg == WinApi.WM_LBUTTONDOWN ? MouseButtons.Left : MouseButtons.Right))
 | |
|                             return;
 | |
|                         break;
 | |
|                     }
 | |
|                 case WinApi.WM_RBUTTONUP:
 | |
|                 case WinApi.WM_LBUTTONUP:
 | |
|                     {
 | |
|                         if (OnMouseUp(ref m, m.Msg == WinApi.WM_LBUTTONDOWN ? MouseButtons.Left : MouseButtons.Right))
 | |
|                             return;
 | |
| 
 | |
|                         break;
 | |
|                     }
 | |
|             }
 | |
| 
 | |
|             base.WndProc(ref m);
 | |
|         }
 | |
| 
 | |
|         protected virtual bool OnMouseUp(ref Message m, MouseButtons param1)
 | |
|         {
 | |
|             if (_MouseDownSelectionPerformed)
 | |
|             {
 | |
|                 _MouseDownSelectionPerformed = false;
 | |
|                 return true;
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
|         private bool _MouseDownSelectionPerformed = false;
 | |
|         protected virtual bool OnMouseDown(ref Message m, MouseButtons button)
 | |
|         {
 | |
|             ToolboxControl lc = this.Control as ToolboxControl;
 | |
|             if (lc == null) return false;
 | |
|             if (m.HWnd != lc.ItemsPanel.Handle)
 | |
|                 return false;
 | |
| 
 | |
|             Point p = new Point(WinApi.LOWORD(m.LParam), WinApi.HIWORD(m.LParam));
 | |
|             BaseItem item = lc.ItemsPanel.HitTest(p);
 | |
|             if (item != null)
 | |
|             {
 | |
|                 SelectComponent(item, (Control.ModifierKeys == Keys.Control || Control.ModifierKeys == Keys.Shift) ? SelectionTypes.Add : SelectionTypes.Primary);
 | |
|                 _MouseDownSelectionPerformed = true;
 | |
|                 return true;
 | |
|             }
 | |
|             else if (!IsControlSelected)
 | |
|             {
 | |
|                 SelectComponent(this.Control, SelectionTypes.Replace);
 | |
|                 //return true;
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         protected virtual void SelectComponent(IComponent comp, SelectionTypes selectionType)
 | |
|         {
 | |
|             ISelectionService selection = (ISelectionService)this.GetService(typeof(ISelectionService));
 | |
|             if (selection != null && comp != null)
 | |
|             {
 | |
|                 ArrayList arr = new ArrayList(1);
 | |
|                 arr.Add(comp);
 | |
|                 selection.SetSelectedComponents(arr, selectionType);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private DesignerActionListCollection _ActionLists = null;
 | |
|         public override DesignerActionListCollection ActionLists
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if (this._ActionLists == null)
 | |
|                 {
 | |
|                     this._ActionLists = new DesignerActionListCollection();
 | |
|                     this._ActionLists.Add(new ToolboxControlActionList(this));
 | |
|                 }
 | |
|                 return this._ActionLists;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected override void PreFilterProperties(System.Collections.IDictionary properties)
 | |
|         {
 | |
|             base.PreFilterProperties(properties);
 | |
| 
 | |
|             properties["Expanded"] = TypeDescriptor.CreateProperty(
 | |
|                 this.GetType(),
 | |
|                 "Expanded",
 | |
|                 typeof(bool),
 | |
|                 new Attribute[]
 | |
|                 {
 | |
|                     new BrowsableAttribute(true), new DefaultValueAttribute(true),
 | |
|                     new CategoryAttribute("Appearance"),
 | |
|                     new DescriptionAttribute(
 | |
|                         "Indicates whether control is expanded and shows items in full size with images and text")
 | |
|                 });
 | |
| 
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Indicates whether Bar is in auto-hide state.
 | |
|         /// </summary>
 | |
|         public bool Expanded
 | |
|         {
 | |
|             set
 | |
|             {
 | |
|                 ShadowProperties["Expanded"] = value;
 | |
|             }
 | |
|             get
 | |
|             {
 | |
|                 return (bool)ShadowProperties["Expanded"];
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void dh_LoadComplete(object sender, EventArgs e)
 | |
|         {
 | |
|             IDesignerHost dh = this.GetService(typeof(IDesignerHost)) as IDesignerHost;
 | |
|             if (dh != null)
 | |
|                 dh.LoadComplete -= new EventHandler(dh_LoadComplete);
 | |
| 
 | |
| #if !TRIAL
 | |
|             string key = GetLicenseKey();
 | |
| 
 | |
|             ToolboxControl tc = (ToolboxControl)this.Control;
 | |
|             if (key != "" && tc != null && tc.LicenseKey == "" && tc.LicenseKey != key)
 | |
|                 TypeDescriptor.GetProperties(tc)["LicenseKey"].SetValue(tc, key);
 | |
| #endif
 | |
|             this.RecalcLayout();
 | |
|         }
 | |
| 
 | |
|         #region Licensing Stuff
 | |
| #if !TRIAL
 | |
|         private string GetLicenseKey()
 | |
|         {
 | |
|             string key = "";
 | |
|             Microsoft.Win32.RegistryKey regkey = Microsoft.Win32.Registry.LocalMachine;
 | |
|             regkey = regkey.OpenSubKey("Software\\DevComponents\\Licenses", false);
 | |
|             if (regkey != null)
 | |
|             {
 | |
|                 object keyValue = regkey.GetValue("DevComponents.DotNetBar.DotNetBarManager2");
 | |
|                 if (keyValue != null)
 | |
|                     key = keyValue.ToString();
 | |
|             }
 | |
|             return key;
 | |
|         }
 | |
|         
 | |
| #endif
 | |
|         #endregion
 | |
|     }
 | |
| 
 | |
|     #region ToolboxItemActionList
 | |
|     internal class ToolboxControlActionList : DesignerActionList
 | |
|     {
 | |
|         private ToolboxControlDesigner _Designer = null;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Initializes a new instance of the AdvTreeActionList class.
 | |
|         /// </summary>
 | |
|         /// <param name="designer"></param>
 | |
|         public ToolboxControlActionList(ToolboxControlDesigner designer)
 | |
|             : base(designer.Component)
 | |
|         {
 | |
|             _Designer = designer;
 | |
|         }
 | |
| 
 | |
|         public override DesignerActionItemCollection GetSortedActionItems()
 | |
|         {
 | |
|             DesignerActionItemCollection items = new DesignerActionItemCollection();
 | |
|             items.Add(new DesignerActionHeaderItem("Items"));
 | |
|             items.Add(new DesignerActionHeaderItem("Position"));
 | |
| 
 | |
|             items.Add(new DesignerActionMethodItem(this, "CreateGroup", "Create Group", "Items", true));
 | |
|             //items.Add(new DesignerActionMethodItem(this, "MoveItemDown", "Move Down", "Position", true));
 | |
|             items.Add(new DesignerActionPropertyItem("Expanded", "Toolbox Expanded?", "Behavior", "Indicates whether toolbox control is expanded and displays items at their full size."));
 | |
|             items.Add(new DesignerActionPropertyItem("ItemDragDropEnabled", "Item Drag and Drop?", "Behavior", "Indicates whether item drag and drop is enabled."));
 | |
| 
 | |
|             items.Add(new DesignerActionPropertyItem("SearchBoxVisible", "Search Visible?", "Appearance", "Indicates whether search text-box is visible."));
 | |
|             items.Add(new DesignerActionPropertyItem("TitleVisible", "Title Visible?", "Appearance", "Indicates whether title bar is visible."));
 | |
|             items.Add(new DesignerActionPropertyItem("MenuVisible", "Menu Visible?", "Appearance", "Indicates whether menu bar is visible."));
 | |
|             return items;
 | |
|         }
 | |
| 
 | |
|         public void CreateGroup()
 | |
|         {
 | |
|             _Designer.CreateGroup();
 | |
|         }
 | |
|         public bool Expanded
 | |
|         {
 | |
|             get { return _Designer.Expanded; }
 | |
|             set { _Designer.Expanded = value; }
 | |
|         }
 | |
|         public bool ItemDragDropEnabled
 | |
|         {
 | |
|             get { return ToolboxControl.ItemDragDropEnabled; }
 | |
|             set { TypeDescriptor.GetProperties(base.Component)["ItemDragDropEnabled"].SetValue(base.Component, value); }
 | |
|         }
 | |
| 
 | |
|         public bool SearchBoxVisible
 | |
|         {
 | |
|             get { return ToolboxControl.SearchBoxVisible; }
 | |
|             set { TypeDescriptor.GetProperties(base.Component)["SearchBoxVisible"].SetValue(base.Component, value); }
 | |
|         }
 | |
| 
 | |
|         public bool TitleVisible
 | |
|         {
 | |
|             get { return ToolboxControl.TitleVisible; }
 | |
|             set { TypeDescriptor.GetProperties(base.Component)["TitleVisible"].SetValue(base.Component, value); }
 | |
|         }
 | |
| 
 | |
|         public bool MenuVisible
 | |
|         {
 | |
|             get { return ToolboxControl.MenuVisible; }
 | |
|             set { TypeDescriptor.GetProperties(base.Component)["MenuVisible"].SetValue(base.Component, value); }
 | |
|         }
 | |
| 
 | |
|         public ToolboxControl ToolboxControl
 | |
|         {
 | |
|             get { return (ToolboxControl)this.Component; }
 | |
|         }
 | |
|     }
 | |
|     #endregion
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Support for TabStrip tabs design-time editor.
 | |
|     /// </summary>
 | |
|     public class ToolboxControlGroupsEditor : CollectionEditor
 | |
|     {
 | |
|         public ToolboxControlGroupsEditor(Type type)
 | |
|             : base(type)
 | |
|         {
 | |
|         }
 | |
|         protected override Type CreateCollectionItemType()
 | |
|         {
 | |
|             return typeof(ToolboxGroup);
 | |
|         }
 | |
|         protected override Type[] CreateNewItemTypes()
 | |
|         {
 | |
|             return new Type[] { typeof(ToolboxGroup) };
 | |
|         }
 | |
|         protected override object CreateInstance(Type itemType)
 | |
|         {
 | |
|             object item = base.CreateInstance(itemType);
 | |
|             if (item is ToolboxGroup)
 | |
|             {
 | |
|                 ToolboxGroup tabItem = item as ToolboxGroup;
 | |
|                 tabItem.Text = "Group";
 | |
|             }
 | |
|             return item;
 | |
|         }
 | |
|     }
 | |
| }
 |