Insert a Thumbnail Preview Record Link in Form

NrvousNrvous Member Posts: 27
Hello again!
After a year I keep trying to add a thumbnail in a form bound to the table "Record Link". The idea is to add an embedded control that passes through a register (a link example x: \ com \ document1.pdf) shows the preview of the file such as Windows XP or IrfanView shown in thumbnail view, irrespective of the extent of file (bmp, jpg, pdf, etc).
I tried to add objects OCX, Automation, etc, and I searched many forums but have not found anything. Could someone help me or give me an answer?. (Kamil, etc)
Thank you very much

Comments

  • NrvousNrvous Member Posts: 27
    No answer here either?, I send a snapshot of search engine links
    Thanks
  • NrvousNrvous Member Posts: 27
    No one has answered? :cry:
  • PeterDPeterD Member Posts: 66
    Try a search on "embed" in the download section.
  • NrvousNrvous Member Posts: 27
    Thanks, I probe the Nav Advanced Image in version 5.1, unfortunately now is not if the component registration problems in 2009 Classic version does not work. Anyway, most of the links are pdf documents, and Nav Advanced Image does not support them. Anyway, thank you very much for your reply, if anyone knows how to develop this component to PDF documents or develop similar component with Visual Studio I would appreciate your communicating.
    Regards,
  • UltramayankUltramayank Member Posts: 28
    What you could do is write a .NET assembly with a function that takes in the path of file and returns the thumbnail as a image, that in-turn can be imported into a temporary blob field to be displayed on the form.
    To extract the Thumbnail from the files take a look at the IExtractImage Interface.
    Let me know if you need further help
    Mayank Bhardwaj
    Visit My Blog at
    http://extremeengineers.net/
  • NrvousNrvous Member Posts: 27
    Dear Mayank. I have seen your website and link IExtract MSDN.
    The idea sounds very good, but I am newbie. NET and I have no idea how to create the component that allows me to do this.
    Once you have created should be recorded as automation? and then pass the parameters of the path in the OnAfterGetRecord to display on your Form.
    We welcome you to tell me step by step if not too much to ask a developer.
    Thank you very much for your attention,
    Best regards
  • UltramayankUltramayank Member Posts: 28
    Dear Nrvous,
    Creating a .NET assembly is preety simple, you just have to create a new class library project in Visual Studio. Sign it with a strong name
    Create the required functions. add a Setup Project to your current solution so that you can save the hassle of registering the assembly manually.
    Once the setup is created you run it to get the class library registered in the GAC.
    Next you are ready to use the Functions in your assembly within nav by using it as a automations.
    I would love to give you a sample project for your purpose, if you have until this weekends. Weekdays are pretty hectic for me. So Let me know if that works for you.
    For the mean time, here are a few links that you'd find usefull.
    Creating a Class Library (DLL)
    Creating a Setup Project
    Mayank Bhardwaj
    Visit My Blog at
    http://extremeengineers.net/
  • NrvousNrvous Member Posts: 27
    Of course I can wait all weekend.
    I'm checking the links you sent me, but I'm too slow :oops: ](*,)
    For your information I have Visual Studio 2010 and Visual Studio C # 2008 Express.
    Greetings and thanks
  • UltramayankUltramayank Member Posts: 28
    Dear Nrvous,

    as promised here's the code to implement IExtractImage interface. You just copy this code and paste it into a new class in your Class Library Project and use the GetThumnail Function to get the BMP image of the file.
    Hope This Helps
    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace vbAccelerator.Components.Shell
    {
    
    	#region ThumbnailCreator
    	/// <summary>
    	/// Summary description for ThumbnailCreator.
    	/// </summary>
    	public class ThumbnailCreator : IDisposable
    	{
    		#region ShellFolder Enumerations
    		[Flags]
    		private enum ESTRRET : int
    		{
    			STRRET_WSTR     = 0x0000,			// Use STRRET.pOleStr
    			STRRET_OFFSET   = 0x0001,			// Use STRRET.uOffset to Ansi
    			STRRET_CSTR     = 0x0002			// Use STRRET.cStr
    		}
    		[Flags]
    		private enum ESHCONTF : int
    		{
    			SHCONTF_FOLDERS = 32,
    			SHCONTF_NONFOLDERS = 64,
    			SHCONTF_INCLUDEHIDDEN = 128
    		}
    
    		[Flags]
    		private enum ESHGDN : int
    		{
    			SHGDN_NORMAL = 0,
    			SHGDN_INFOLDER = 1,
    			SHGDN_FORADDRESSBAR = 16384,
    			SHGDN_FORPARSING = 32768
    		}
    		[Flags]
    		private enum ESFGAO : int
    		{
    			SFGAO_CANCOPY = 1,
    			SFGAO_CANMOVE = 2,
    			SFGAO_CANLINK = 4,
    			SFGAO_CANRENAME = 16,
    			SFGAO_CANDELETE = 32,
    			SFGAO_HASPROPSHEET = 64,
    			SFGAO_DROPTARGET = 256,
    			SFGAO_CAPABILITYMASK = 375,
    			SFGAO_LINK = 65536,
    			SFGAO_SHARE = 131072,
    			SFGAO_READONLY = 262144,
    			SFGAO_GHOSTED = 524288,
    			SFGAO_DISPLAYATTRMASK = 983040,
    			SFGAO_FILESYSANCESTOR = 268435456,
    			SFGAO_FOLDER = 536870912,
    			SFGAO_FILESYSTEM = 1073741824,
    			SFGAO_HASSUBFOLDER = -2147483648,
    			SFGAO_CONTENTSMASK = -2147483648,
    			SFGAO_VALIDATE = 16777216,
    			SFGAO_REMOVABLE = 33554432,
    			SFGAO_COMPRESSED = 67108864
    		}
    		#endregion
    
    		#region IExtractImage Enumerations
    		private enum EIEIFLAG
    		{
    			IEIFLAG_ASYNC       = 0x0001,      // ask the extractor if it supports ASYNC extract (free threaded)
    			IEIFLAG_CACHE       = 0x0002,      // returned from the extractor if it does NOT cache the thumbnail
    			IEIFLAG_ASPECT      = 0x0004,      // passed to the extractor to beg it to render to the aspect ratio of the supplied rect
    			IEIFLAG_OFFLINE     = 0x0008,      // if the extractor shouldn't hit the net to get any content neede for the rendering
    			IEIFLAG_GLEAM       = 0x0010,     // does the image have a gleam ? this will be returned if it does
    			IEIFLAG_SCREEN      = 0x0020,      // render as if for the screen  (this is exlusive with IEIFLAG_ASPECT )
    			IEIFLAG_ORIGSIZE    = 0x0040,      // render to the approx size passed, but crop if neccessary
    			IEIFLAG_NOSTAMP     = 0x0080,      // returned from the extractor if it does NOT want an icon stamp on the thumbnail
    			IEIFLAG_NOBORDER    = 0x0100,      // returned from the extractor if it does NOT want an a border around the thumbnail
    			IEIFLAG_QUALITY     = 0x0200      // passed to the Extract method to indicate that a slower, higher quality image is desired, re-compute the thumbnail
    		}
    		#endregion
    
    		#region ShellFolder Structures 
    		[StructLayoutAttribute(LayoutKind.Sequential, Pack=4, Size=0, CharSet=CharSet.Auto)]
    		private struct STRRET_CSTR
    		{
    			public ESTRRET uType;
    			[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=520)]
    			public byte[]			cStr;
    		}
    	
    		[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Auto)]
    		private struct STRRET_ANY
    		{
    			[FieldOffset(0)] 
    			public ESTRRET uType;
    			[FieldOffset(4)] 
    			public IntPtr pOLEString; 
    		}
    
    		[StructLayoutAttribute(LayoutKind.Sequential)]
    		private struct SIZE 
    		{
    			public int cx;
    			public int cy;
    		}
    		#endregion
    
    		#region Com Interop for IUnknown
    		[ComImport, Guid("00000000-0000-0000-C000-000000000046")]
    		[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    		private interface IUnknown
    		{
    			[PreserveSig]
    			IntPtr QueryInterface(ref Guid riid, out IntPtr pVoid);
    		
    			[PreserveSig]
    			IntPtr AddRef();
    
    			[PreserveSig]
    			IntPtr Release();
    		}
    		#endregion
    
    		#region COM Interop for IMalloc
    		[ComImportAttribute()]
    		[GuidAttribute("00000002-0000-0000-C000-000000000046")]
    		[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    		//helpstring("IMalloc interface")
    		private interface IMalloc
    		{
    			[PreserveSig]
    			IntPtr Alloc(int cb);
    
    			[PreserveSig]
    			IntPtr Realloc(
    				IntPtr pv,
    				int cb);
    		
    			[PreserveSig]
    			void Free(IntPtr pv);
    
    			[PreserveSig]
    			int GetSize(IntPtr pv);
    
    			[PreserveSig]
    			int DidAlloc(IntPtr pv);
    
    			[PreserveSig]
    			void  HeapMinimize();
    		};
    		#endregion
    
    		#region COM Interop for IEnumIDList
    		[ComImportAttribute()]
    		[GuidAttribute("000214F2-0000-0000-C000-000000000046")]
    		[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    		//helpstring("IEnumIDList interface")
    		private interface IEnumIDList
    		{
    			[PreserveSig]
    			int Next(
    				int celt, 
    				ref IntPtr rgelt, 
    				out int pceltFetched);
    
    			void Skip(
    				int celt);
    
    			void Reset();
        
    			void Clone(
    				ref IEnumIDList ppenum);
    		};
    		#endregion
    
    		#region COM Interop for IShellFolder
    		[ComImportAttribute()]
    		[GuidAttribute("000214E6-0000-0000-C000-000000000046")]
    		[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    		//helpstring("IShellFolder interface")
    		private interface IShellFolder
    		{
    			void ParseDisplayName(
    				IntPtr hwndOwner, 
    				IntPtr pbcReserved, 
    				[MarshalAs(UnmanagedType.LPWStr)] string lpszDisplayName,
    				out int pchEaten, 
    				out IntPtr ppidl, 
    				out int pdwAttributes);
    
    			void EnumObjects(
    				IntPtr hwndOwner, 
    				[MarshalAs(UnmanagedType.U4)] ESHCONTF grfFlags,
    				ref IEnumIDList ppenumIDList
    				);
    
    			void BindToObject(
    				IntPtr pidl, 
    				IntPtr pbcReserved, 
    				ref Guid riid, 
    				ref IShellFolder ppvOut);
    
    			void BindToStorage(
    				IntPtr pidl, 
    				IntPtr pbcReserved, 
    				ref Guid riid, 
    				IntPtr ppvObj
    				);
    
    			[PreserveSig]
    			int CompareIDs(
    				IntPtr lParam, 
    				IntPtr pidl1, 
    				IntPtr pidl2);
    
    			void CreateViewObject(
    				IntPtr hwndOwner, 
    				ref Guid riid, 
    				IntPtr ppvOut);
    
    			void GetAttributesOf(
    				int cidl, 
    				IntPtr apidl, 
    				[MarshalAs(UnmanagedType.U4)] ref ESFGAO rgfInOut); 
    
    			void GetUIObjectOf(
    				IntPtr hwndOwner, 
    				int cidl, 
    				ref IntPtr apidl, 
    				ref Guid riid, 
    				out int prgfInOut, 
    				ref IUnknown ppvOut);
    
    			void GetDisplayNameOf(
    				IntPtr pidl, 
    				[MarshalAs(UnmanagedType.U4)] ESHGDN uFlags,  
    				ref STRRET_CSTR lpName);
    
    			void SetNameOf(
    				IntPtr hwndOwner, 
    				IntPtr pidl,
    				[MarshalAs(UnmanagedType.LPWStr)] string lpszName,
    				[MarshalAs(UnmanagedType.U4)] ESHCONTF uFlags,
    				ref IntPtr ppidlOut);
    		};
    		#endregion
    
    		#region COM Interop for IExtractImage
    		[ComImportAttribute()]
    		[GuidAttribute("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1")]
    		[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    		//helpstring("IExtractImage"),
    		private interface IExtractImage
    		{
    			void GetLocation(
    				[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPathBuffer,
    				int cch,
    				ref int pdwPriority,
    				ref SIZE prgSize,
    				int dwRecClrDepth,
    				ref int pdwFlags);
    
    			void Extract(
    				out IntPtr phBmpThumbnail);
    		}
    		#endregion
    	
    		#region UnManagedMethods for IShellFolder
    		private class UnManagedMethods
    		{
    			[DllImport("shell32", CharSet = CharSet.Auto)]
    			internal extern static int SHGetMalloc(out IMalloc ppMalloc);
    
    			[DllImport("shell32", CharSet = CharSet.Auto)]
    			internal extern static int SHGetDesktopFolder(out IShellFolder ppshf);
    		
    			[DllImport("shell32", CharSet = CharSet.Auto)]
    			internal extern static int SHGetPathFromIDList (
    				IntPtr pidl, 
    				StringBuilder pszPath);
    
    			[DllImport("gdi32", CharSet = CharSet.Auto)]
    			internal extern static int DeleteObject (
    				IntPtr hObject
    				);
    		}	
    		#endregion
    
    		#region Member Variables
    		private IMalloc alloc = null;
    		private bool disposed = false;
    		private System.Drawing.Size desiredSize = new System.Drawing.Size(100,100);
    		private System.Drawing.Bitmap thumbNail = null;
    		#endregion
    
    		#region Implementation
    		public System.Drawing.Bitmap ThumbNail
    		{
    			get
    			{
    				return thumbNail;
    			}
    		}
    
    
    		public System.Drawing.Size DesiredSize
    		{
    			get
    			{
    				return desiredSize;
    			}
    			set
    			{
    				desiredSize = value;
    			}
    		}
    
    		private IMalloc Allocator
    		{
    			get
    			{
    				if (!disposed)
    				{
    					if (alloc == null)
    					{
    						UnManagedMethods.SHGetMalloc(out alloc);					
    					}
    				}
    				else
    				{
    					System.Diagnostics.Debug.Assert(false, "Object has been disposed.");
    				}
    				return alloc;
    			}
    		}
    
    		public System.Drawing.Bitmap GetThumbNail(
    			string file
    			)
    		{
    			if ((!File.Exists(file)) && (!Directory.Exists(file)))
    			{
    				throw new FileNotFoundException(
    					String.Format("The file '{0}' does not exist", file),
    					file);
    			}
    
    			if (thumbNail != null)
    			{
    				thumbNail.Dispose();
    				thumbNail = null;
    			}
    
    			IShellFolder folder = null;
    			try
    			{
    				folder = getDesktopFolder;
    			}
    			catch (Exception ex)
    			{
    				throw ex;
    			}
    
    			if (folder != null)
    			{
    				IntPtr pidlMain = IntPtr.Zero;
    				try
    				{
    					int cParsed = 0;
    					int pdwAttrib = 0;
    					string filePath = Path.GetDirectoryName(file);
    					pidlMain = IntPtr.Zero;
    					folder.ParseDisplayName(
    						IntPtr.Zero, 
    						IntPtr.Zero, 
    						filePath, 
    						out cParsed, 
    						out pidlMain,
    						out pdwAttrib);
    				}
    				catch (Exception ex)
    				{
    					Marshal.ReleaseComObject(folder);
    					throw ex;
    				}
    
    				if (pidlMain != IntPtr.Zero)
    				{
    					// IShellFolder:
    					Guid iidShellFolder = new Guid("000214E6-0000-0000-C000-000000000046");					
    					IShellFolder item = null;
    
    					try
    					{
    						folder.BindToObject(pidlMain, IntPtr.Zero, ref iidShellFolder, ref item);
    					}
    					catch (Exception ex)
    					{
    						Marshal.ReleaseComObject(folder);
    						Allocator.Free(pidlMain);
    						throw ex;
    					}
    
    					if (item != null)
    					{
    						//
    						IEnumIDList idEnum = null;
    						try
    						{
    							item.EnumObjects(
    								IntPtr.Zero, 
    								(ESHCONTF.SHCONTF_FOLDERS | ESHCONTF.SHCONTF_NONFOLDERS),
    								ref idEnum);
    						}
    						catch (Exception ex)
    						{
    							Marshal.ReleaseComObject(folder);
    							Allocator.Free(pidlMain);
    							throw ex;
    						}
    						
    						if (idEnum != null)
    						{
    							// start reading the enum:
    							int hRes = 0;
    							IntPtr pidl = IntPtr.Zero;
    							int fetched = 0;
    							bool complete = false;
    							while (!complete)
    							{
    								hRes = idEnum.Next(1, ref pidl, out fetched);
    								if (hRes != 0)
    								{
    									pidl = IntPtr.Zero;
    									complete = true;
    								}
    								else
    								{
    									if (getThumbNail(file, pidl, item))
    									{
    										complete = true;
    									}
    								}
    								if (pidl != IntPtr.Zero)
    								{
    									Allocator.Free(pidl);
    								}
    							}
    
    							Marshal.ReleaseComObject(idEnum);
    						}
    
    
    						Marshal.ReleaseComObject(item);
    					}
    
    					Allocator.Free(pidlMain);
    				}
    
    				Marshal.ReleaseComObject(folder);
    			}
    			return thumbNail;
    		}
    
    		private bool getThumbNail(
    			string file,
    			IntPtr pidl, 
    			IShellFolder item
    			)
    		{
    			IntPtr hBmp = IntPtr.Zero;
    			IExtractImage extractImage = null;
    
    			try
    			{
    				string pidlPath = PathFromPidl(pidl);
    				if (Path.GetFileName(pidlPath).ToUpper().Equals(Path.GetFileName(file).ToUpper()))
    				{
    					// we have the item:								
    					IUnknown iunk = null;
    					int prgf = 0;
    					Guid iidExtractImage = new Guid("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1");
    					item.GetUIObjectOf(
    						IntPtr.Zero, 
    						1, 
    						ref pidl, 
    						ref iidExtractImage,
    						out prgf,
    						ref iunk);				
    					extractImage = (IExtractImage)iunk;
    					
    					if (extractImage != null)
    					{
    						Console.WriteLine("Got an IExtractImage object!");
    						SIZE sz = new SIZE();
    						sz.cx = desiredSize.Width;
    						sz.cy = desiredSize.Height;
    						StringBuilder location = new StringBuilder(260, 260);
    						int priority = 0;
    						int requestedColourDepth = 32;
    						EIEIFLAG flags = EIEIFLAG.IEIFLAG_ASPECT | EIEIFLAG.IEIFLAG_SCREEN;
    						int uFlags = (int)flags;
    						
    						extractImage.GetLocation(
    							location, 
    							location.Capacity, 
    							ref priority,
    							ref sz,
    							requestedColourDepth,
    							ref uFlags);
    
    						extractImage.Extract(out hBmp);						
    						if (hBmp != IntPtr.Zero)
    						{
    							// create the image object:
    							thumbNail = System.Drawing.Bitmap.FromHbitmap(hBmp);
    							// is thumbNail owned by the Bitmap?
    						}
    
    						Marshal.ReleaseComObject(extractImage);
    						extractImage = null;
    					}
    					return true;
    				}
    				else
    				{
    					return false;
    				}
    			}
    			catch (Exception ex)
    			{
    				if (hBmp != IntPtr.Zero)
    				{
    					UnManagedMethods.DeleteObject(hBmp);
    				}
    				if (extractImage != null)
    				{
    					Marshal.ReleaseComObject(extractImage);
    				}
    				throw ex;
    			}
    		}
    
    		private string PathFromPidl(
    			IntPtr pidl
    			)
    		{
    			StringBuilder path = new StringBuilder(260, 260);
    			int result = UnManagedMethods.SHGetPathFromIDList(pidl, path);
    			if (result == 0)
    			{
    				return string.Empty;
    			}
    			else
    			{
    				return path.ToString();	
    			}
    		}
    	
    		private IShellFolder getDesktopFolder
    		{
    			get
    			{
    				IShellFolder ppshf;
    				int r = UnManagedMethods.SHGetDesktopFolder(out ppshf);
    				return ppshf;
    			}
    		}
    		#endregion
    
    		#region Constructor, Destructor, Dispose							 
    		public ThumbnailCreator()
    		{
    		}
    
    		public void Dispose()
    		{
    			if (!disposed)
    			{
    				if (alloc != null)
    				{
    					Marshal.ReleaseComObject(alloc);
    				}
    				alloc = null;
    
    				if (thumbNail != null)
    				{
    					thumbNail.Dispose();
    				}
    
    				disposed = true;
    			}
    		}
    
    		~ThumbnailCreator()
    		{
    			Dispose();
    		}
    		#endregion
    	}
    	#endregion
    }
    
    
    Mayank Bhardwaj
    Visit My Blog at
    http://extremeengineers.net/
  • NrvousNrvous Member Posts: 27
    Dear Ultramayank:
    First I want to thank the effort and patience you have with a novice (me) in Visual C #. I tried to make the class (dll) in Visual C # (2008 Express and 2010), as the links you sent me but when you compile the project I get the following errors:
    Error 1 The type or namespace name 'Drawing' does not exist in the namespace 'System' (are you missing an assembly reference?
    Could you tell me the problem?
    Thank you very much for your attention and patience
    PS: The error is the same in Visual C # 2008 and Visual C # 2010
  • NrvousNrvous Member Posts: 27
    Dear UltraMayank:
    I've managed to add the reference, which was looking for the error error CS0234: The type or namespace name 'Drawing' does not exist in the namespace 'System' (are you missing an assembly reference?) By adding the reference System . Drawing.
    I created the complete solution, and now try to generate the setup to register the key, which is the fastest way?.
    I tried to make an installation wizard, but do not know if this is the right way.
    Thank you very much
  • UltramayankUltramayank Member Posts: 28
    Dear Nrvous,
    well creating the setup is a pretty simple process, you just have to add a setup project in your solution, add the primary output of your mail project in the correct and desired location in the Filesystem manager. Add the custom actions, and that is about it. You are good to go.
    If your "way" includes these steps, you could bet its right.
    Glad that I could help, you are welcome.
    Mayank Bhardwaj
    Visit My Blog at
    http://extremeengineers.net/
  • NrvousNrvous Member Posts: 27
    Dear Ultramayank:
    Perform the setup and installation, but can not find in Navision how to reference the dll, I image (2 files with two testing facilities).
    As a reference and as a call to the DLL (not seen in Automation)
    Thank you very much [-o<
  • NrvousNrvous Member Posts: 27
    Dear Mayank:
    I still can continue with the installation and reference of the dll in Navision. Could you send a private mail so you can see where I'm wrong?.

    Waiting for your news,
    Best regards

    Thanks
  • SogSog Member Posts: 1,023
    have you registered the dll in windows?
    if not, run cmd and type the following:

    regsvr32 “C:\Archivos de programa\thumbnailextractor\Thumbnailextractor3.dll”
    |Pressing F1 is so much faster than opening your browser|
    |To-Increase|
  • NrvousNrvous Member Posts: 27
    Dear Sog:

    When the installation is created, it automatically registers the dll?
    Still, it shows me this error ... something I'm doing wrong and what is not ](*,)

    error:
    ThumbnailExtractor3.dll was unloaded but not found the DLL entry point registerserver. Unable to register this file

    Thanks for your reply

    Regards,
  • Lilo20Lilo20 Member Posts: 2
    Hi,

    have somebody create successfully the dll file?
    I can’t see the properties and functions in NAV.
    Somebody an idea or a dll that works?

    Yours sincerely
  • NrvousNrvous Member Posts: 27
    Hi;

    It seems that no one was able to record or generate the dll correctly.
    I'm a newbie. NET and I followed the instructions Ultramayank, but still can not register the dll or use in Navision.

    If anyone is encouraged ... [-o<

    Regards,
  • Lilo20Lilo20 Member Posts: 2
    you must create them and register it like this , then the dll is avalible with properties and functions.
  • NrvousNrvous Member Posts: 27
    Ok, thanks I'll try from the beginning
  • agnetagnet Member Posts: 3
    Hi,

    Can someone help me please. I registered the dll and that's ok. Now the problem is when I try to access the automation to use it in my form, I don't see any classes to be used
Sign In or Register to comment.