469 lines
22 KiB
C#
469 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security;
|
|
using System.Windows.Forms;
|
|
using System.Runtime.CompilerServices;
|
|
using System.IO;
|
|
|
|
namespace ExtendedWebBrowser2
|
|
{
|
|
#pragma warning disable
|
|
class UnsafeNativeMethods
|
|
{
|
|
private UnsafeNativeMethods()
|
|
{
|
|
}
|
|
//public struct _RemotableHandle
|
|
//{
|
|
// public int fContext;
|
|
// public __MIDL_IWinTypes_0009 u;
|
|
//}
|
|
//public struct __MIDL_IWinTypes_0009
|
|
//{
|
|
// public int hInproc;
|
|
// public int hRemote;
|
|
//}
|
|
public struct tagPOINT
|
|
{
|
|
public int x;
|
|
public int y;
|
|
}
|
|
|
|
[ComImport, Guid("C4D244B0-D43E-11CF-893B-00AA00BDCE1A"), InterfaceType((short)1)]
|
|
public interface IDocHostShowUI
|
|
{
|
|
[return: MarshalAs(UnmanagedType.I4)]
|
|
[PreserveSig]
|
|
int ShowMessage(
|
|
int hwnd,
|
|
[MarshalAs(UnmanagedType.LPWStr)] string lpstrText,
|
|
[MarshalAs(UnmanagedType.LPWStr)] string lpstrCaption,
|
|
[MarshalAs(UnmanagedType.U4)] uint dwType,
|
|
[MarshalAs(UnmanagedType.LPWStr)] string lpstrHelpFile,
|
|
[MarshalAs(UnmanagedType.U4)] uint dwHelpContext,
|
|
[In, Out] ref int lpResult);
|
|
[return: MarshalAs(UnmanagedType.I4)]
|
|
[PreserveSig]
|
|
int ShowHelp(
|
|
int hwnd,
|
|
[MarshalAs(UnmanagedType.LPWStr)] string pszHelpFile,
|
|
[MarshalAs(UnmanagedType.U4)] uint uCommand,
|
|
[MarshalAs(UnmanagedType.U4)] uint dwData,
|
|
[In, MarshalAs(UnmanagedType.Struct)] tagPOINT ptMouse,
|
|
[Out, MarshalAs(UnmanagedType.IDispatch)] object pDispatchObjectHit);
|
|
}
|
|
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
|
|
SuppressUnmanagedCodeSecurity,
|
|
Guid("7FD52380-4E07-101B-AE2D-08002B2EC713")]
|
|
public interface IPersistStreamInit
|
|
{
|
|
void GetClassID(out Guid pClassID);
|
|
[PreserveSig]
|
|
int IsDirty();
|
|
void Load([In, MarshalAs(UnmanagedType.Interface)] IStream pstm);
|
|
void Save([In, MarshalAs(UnmanagedType.Interface)] IStream pstm, [In, MarshalAs(UnmanagedType.Bool)] bool fClearDirty);
|
|
void GetSizeMax([Out, MarshalAs(UnmanagedType.LPArray)] long pcbSize);
|
|
void InitNew();
|
|
}
|
|
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000C-0000-0000-C000-000000000046")]
|
|
public interface IStream
|
|
{
|
|
int Read(IntPtr buf, int len);
|
|
int Write(IntPtr buf, int len);
|
|
[return: MarshalAs(UnmanagedType.I8)]
|
|
long Seek([In, MarshalAs(UnmanagedType.I8)] long dlibMove, int dwOrigin);
|
|
void SetSize([In, MarshalAs(UnmanagedType.I8)] long libNewSize);
|
|
[return: MarshalAs(UnmanagedType.I8)]
|
|
long CopyTo([In, MarshalAs(UnmanagedType.Interface)] IStream pstm, [In, MarshalAs(UnmanagedType.I8)] long cb, [Out, MarshalAs(UnmanagedType.LPArray)] long[] pcbRead);
|
|
void Commit(int grfCommitFlags);
|
|
void Revert();
|
|
void LockRegion([In, MarshalAs(UnmanagedType.I8)] long libOffset, [In, MarshalAs(UnmanagedType.I8)] long cb, int dwLockType);
|
|
void UnlockRegion([In, MarshalAs(UnmanagedType.I8)] long libOffset, [In, MarshalAs(UnmanagedType.I8)] long cb, int dwLockType);
|
|
void Stat([Out] STATSTG pStatstg, int grfStatFlag);
|
|
[return: MarshalAs(UnmanagedType.Interface)]
|
|
IStream Clone();
|
|
}
|
|
public class ComStreamFromDataStream : IStream
|
|
{
|
|
// Methods
|
|
protected ComStreamFromDataStream()
|
|
{
|
|
this.virtualPosition = -1;
|
|
}
|
|
|
|
public ComStreamFromDataStream(Stream dataStream)
|
|
{
|
|
this.virtualPosition = -1;
|
|
if (dataStream == null)
|
|
{
|
|
throw new ArgumentNullException("dataStream");
|
|
}
|
|
this.dataStream = dataStream;
|
|
}
|
|
|
|
private void ActualizeVirtualPosition()
|
|
{
|
|
if (this.virtualPosition != -1)
|
|
{
|
|
if (this.virtualPosition > this.dataStream.Length)
|
|
{
|
|
this.dataStream.SetLength(this.virtualPosition);
|
|
}
|
|
this.dataStream.Position = this.virtualPosition;
|
|
this.virtualPosition = -1;
|
|
}
|
|
}
|
|
|
|
public IStream Clone()
|
|
{
|
|
ComStreamFromDataStream.NotImplemented();
|
|
return null;
|
|
}
|
|
|
|
public void Commit(int grfCommitFlags)
|
|
{
|
|
this.dataStream.Flush();
|
|
this.ActualizeVirtualPosition();
|
|
}
|
|
|
|
public long CopyTo(IStream pstm, long cb, long[] pcbRead)
|
|
{
|
|
int num1 = 0x1000;
|
|
IntPtr ptr1 = Marshal.AllocHGlobal(num1);
|
|
if (ptr1 == IntPtr.Zero)
|
|
{
|
|
throw new OutOfMemoryException();
|
|
}
|
|
long num2 = 0;
|
|
try
|
|
{
|
|
while (num2 < cb)
|
|
{
|
|
int num3 = num1;
|
|
if ((num2 + num3) > cb)
|
|
{
|
|
num3 = (int)(cb - num2);
|
|
}
|
|
int num4 = this.Read(ptr1, num3);
|
|
if (num4 == 0)
|
|
{
|
|
goto Label_006C;
|
|
}
|
|
if (pstm.Write(ptr1, num4) != num4)
|
|
{
|
|
throw ComStreamFromDataStream.EFail("Wrote an incorrect number of bytes");
|
|
}
|
|
num2 += num4;
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(ptr1);
|
|
}
|
|
Label_006C:
|
|
if ((pcbRead != null) && (pcbRead.Length > 0))
|
|
{
|
|
pcbRead[0] = num2;
|
|
}
|
|
return num2;
|
|
}
|
|
|
|
protected static ExternalException EFail(string msg)
|
|
{
|
|
ExternalException exception1 = new ExternalException(msg, -2147467259);
|
|
throw exception1;
|
|
}
|
|
|
|
public Stream GetDataStream()
|
|
{
|
|
return this.dataStream;
|
|
}
|
|
|
|
public void LockRegion(long libOffset, long cb, int dwLockType)
|
|
{
|
|
}
|
|
|
|
protected static void NotImplemented()
|
|
{
|
|
ExternalException exception1 = new ExternalException("Not implemented.", -2147467263);
|
|
throw exception1;
|
|
}
|
|
|
|
public int Read(IntPtr buf, int length)
|
|
{
|
|
byte[] buffer1 = new byte[length];
|
|
int num1 = this.Read(buffer1, length);
|
|
Marshal.Copy(buffer1, 0, buf, length);
|
|
return num1;
|
|
}
|
|
|
|
public int Read(byte[] buffer, int length)
|
|
{
|
|
this.ActualizeVirtualPosition();
|
|
return this.dataStream.Read(buffer, 0, length);
|
|
}
|
|
|
|
public void Revert()
|
|
{
|
|
ComStreamFromDataStream.NotImplemented();
|
|
}
|
|
|
|
public long Seek(long offset, int origin)
|
|
{
|
|
long num1 = this.virtualPosition;
|
|
if (this.virtualPosition == -1)
|
|
{
|
|
num1 = this.dataStream.Position;
|
|
}
|
|
long num2 = this.dataStream.Length;
|
|
switch (origin)
|
|
{
|
|
case 0:
|
|
{
|
|
if (offset > num2)
|
|
{
|
|
this.virtualPosition = offset;
|
|
break;
|
|
}
|
|
this.dataStream.Position = offset;
|
|
this.virtualPosition = -1;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
if ((offset + num1) > num2)
|
|
{
|
|
this.virtualPosition = offset + num1;
|
|
break;
|
|
}
|
|
this.dataStream.Position = num1 + offset;
|
|
this.virtualPosition = -1;
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
if (offset > 0)
|
|
{
|
|
this.virtualPosition = num2 + offset;
|
|
break;
|
|
}
|
|
this.dataStream.Position = num2 + offset;
|
|
this.virtualPosition = -1;
|
|
break;
|
|
}
|
|
}
|
|
if (this.virtualPosition != -1)
|
|
{
|
|
return this.virtualPosition;
|
|
}
|
|
return this.dataStream.Position;
|
|
}
|
|
|
|
public void SetSize(long value)
|
|
{
|
|
this.dataStream.SetLength(value);
|
|
}
|
|
|
|
public void Stat(STATSTG pstatstg, int grfStatFlag)
|
|
{
|
|
pstatstg.type = 2;
|
|
pstatstg.cbSize = this.dataStream.Length;
|
|
pstatstg.grfLocksSupported = 2;
|
|
}
|
|
|
|
public void UnlockRegion(long libOffset, long cb, int dwLockType)
|
|
{
|
|
}
|
|
|
|
public int Write(IntPtr buf, int length)
|
|
{
|
|
byte[] buffer1 = new byte[length];
|
|
Marshal.Copy(buf, buffer1, 0, length);
|
|
return this.Write(buffer1, length);
|
|
}
|
|
|
|
public int Write(byte[] buffer, int length)
|
|
{
|
|
this.ActualizeVirtualPosition();
|
|
this.dataStream.Write(buffer, 0, length);
|
|
return length;
|
|
}
|
|
// Fields
|
|
protected Stream dataStream;
|
|
private long virtualPosition;
|
|
}
|
|
[ComImport, TypeLibType((short)0x1010), InterfaceType((short)2), Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D")]
|
|
public interface DWebBrowserEvents2
|
|
{
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x66)]
|
|
void StatusTextChange([In, MarshalAs(UnmanagedType.BStr)] string Text);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x6c)]
|
|
void ProgressChange([In] int Progress, [In] int ProgressMax);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x69)]
|
|
void CommandStateChange([In] int Command, [In] bool Enable);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x6a)]
|
|
void DownloadBegin();
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x68)]
|
|
void DownloadComplete();
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x71)]
|
|
void TitleChange([In, MarshalAs(UnmanagedType.BStr)] string Text);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x70)]
|
|
void PropertyChange([In, MarshalAs(UnmanagedType.BStr)] string szProperty);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(250)]
|
|
void BeforeNavigate2([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In, MarshalAs(UnmanagedType.Struct)] ref object URL, [In, MarshalAs(UnmanagedType.Struct)] ref object Flags, [In, MarshalAs(UnmanagedType.Struct)] ref object TargetFrameName, [In, MarshalAs(UnmanagedType.Struct)] ref object PostData, [In, MarshalAs(UnmanagedType.Struct)] ref object Headers, [In, Out] ref bool Cancel);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0xfb)]
|
|
void NewWindow2([In, Out, MarshalAs(UnmanagedType.IDispatch)] ref object ppDisp, [In, Out] ref bool Cancel);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0xfc)]
|
|
void NavigateComplete2([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In, MarshalAs(UnmanagedType.Struct)] ref object URL);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x103)]
|
|
void DocumentComplete([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In, MarshalAs(UnmanagedType.Struct)] ref object URL);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0xfd)]
|
|
void OnQuit();
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0xfe)]
|
|
void OnVisible([In] bool Visible);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0xff)]
|
|
void OnToolBar([In] bool ToolBar);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x100)]
|
|
void OnMenuBar([In] bool MenuBar);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x101)]
|
|
void OnStatusBar([In] bool StatusBar);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x102)]
|
|
void OnFullScreen([In] bool FullScreen);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(260)]
|
|
void OnTheaterMode([In] bool TheaterMode);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x106)]
|
|
void WindowSetResizable([In] bool Resizable);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x108)]
|
|
void WindowSetLeft([In] int Left);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x109)]
|
|
void WindowSetTop([In] int Top);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x10a)]
|
|
void WindowSetWidth([In] int Width);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x10b)]
|
|
void WindowSetHeight([In] int Height);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x107)]
|
|
void WindowClosing([In] bool IsChildWindow, [In, Out] ref bool Cancel);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x10c)]
|
|
void ClientToHostWindow([In, Out] ref int CX, [In, Out] ref int CY);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x10d)]
|
|
void SetSecureLockIcon([In] int SecureLockIcon);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(270)]
|
|
void FileDownload([In, Out] ref bool Cancel);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x10f)]
|
|
void NavigateError([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In, MarshalAs(UnmanagedType.Struct)] ref object URL, [In, MarshalAs(UnmanagedType.Struct)] ref object Frame, [In, MarshalAs(UnmanagedType.Struct)] ref object StatusCode, [In, Out] ref bool Cancel);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0xe1)]
|
|
void PrintTemplateInstantiation([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0xe2)]
|
|
void PrintTemplateTeardown([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0xe3)]
|
|
void UpdatePageStatus([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In, MarshalAs(UnmanagedType.Struct)] ref object nPage, [In, MarshalAs(UnmanagedType.Struct)] ref object fDone);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x110)]
|
|
void PrivacyImpactedStateChange([In] bool bImpacted);
|
|
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x111)]
|
|
void NewWindow3([In, Out, MarshalAs(UnmanagedType.IDispatch)] ref object ppDisp, [In, Out] ref bool Cancel, [In] uint dwFlags, [In, MarshalAs(UnmanagedType.BStr)] string bstrUrlContext, [In, MarshalAs(UnmanagedType.BStr)] string bstrUrl);
|
|
}
|
|
|
|
[ComImport, SuppressUnmanagedCodeSecurity, TypeLibType(TypeLibTypeFlags.FOleAutomation | (TypeLibTypeFlags.FDual | TypeLibTypeFlags.FHidden)), Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")]
|
|
public interface IWebBrowser2
|
|
{
|
|
[DispId(100)]
|
|
void GoBack();
|
|
[DispId(0x65)]
|
|
void GoForward();
|
|
[DispId(0x66)]
|
|
void GoHome();
|
|
[DispId(0x67)]
|
|
void GoSearch();
|
|
[DispId(0x68)]
|
|
void Navigate([In] string Url, [In] ref object flags, [In] ref object targetFrameName, [In] ref object postData, [In] ref object headers);
|
|
[DispId(-550)]
|
|
void Refresh();
|
|
[DispId(0x69)]
|
|
void Refresh2([In] ref object level);
|
|
[DispId(0x6a)]
|
|
void Stop();
|
|
[DispId(200)]
|
|
object Application { [return: MarshalAs(UnmanagedType.IDispatch)] get; }
|
|
[DispId(0xc9)]
|
|
object Parent { [return: MarshalAs(UnmanagedType.IDispatch)] get; }
|
|
[DispId(0xca)]
|
|
object Container { [return: MarshalAs(UnmanagedType.IDispatch)] get; }
|
|
[DispId(0xcb)]
|
|
object Document { [return: MarshalAs(UnmanagedType.IDispatch)] get; }
|
|
[DispId(0xcc)]
|
|
bool TopLevelContainer { get; }
|
|
[DispId(0xcd)]
|
|
string Type { get; }
|
|
[DispId(0xce)]
|
|
int Left { get; set; }
|
|
[DispId(0xcf)]
|
|
int Top { get; set; }
|
|
[DispId(0xd0)]
|
|
int Width { get; set; }
|
|
[DispId(0xd1)]
|
|
int Height { get; set; }
|
|
[DispId(210)]
|
|
string LocationName { get; }
|
|
[DispId(0xd3)]
|
|
string LocationURL { get; }
|
|
[DispId(0xd4)]
|
|
bool Busy { get; }
|
|
[DispId(300)]
|
|
void Quit();
|
|
[DispId(0x12d)]
|
|
void ClientToWindow(out int pcx, out int pcy);
|
|
[DispId(0x12e)]
|
|
void PutProperty([In] string property, [In] object vtValue);
|
|
[DispId(0x12f)]
|
|
object GetProperty([In] string property);
|
|
[DispId(0)]
|
|
string Name { get; }
|
|
[DispId(-515)]
|
|
int HWND { get; }
|
|
[DispId(400)]
|
|
string FullName { get; }
|
|
[DispId(0x191)]
|
|
string Path { get; }
|
|
[DispId(0x192)]
|
|
bool Visible { get; set; }
|
|
[DispId(0x193)]
|
|
bool StatusBar { get; set; }
|
|
[DispId(0x194)]
|
|
string StatusText { get; set; }
|
|
[DispId(0x195)]
|
|
int ToolBar { get; set; }
|
|
[DispId(0x196)]
|
|
bool MenuBar { get; set; }
|
|
[DispId(0x197)]
|
|
bool FullScreen { get; set; }
|
|
[DispId(500)]
|
|
void Navigate2([In] ref object URL, [In] ref object flags, [In] ref object targetFrameName, [In] ref object postData, [In] ref object headers);
|
|
[DispId(0x1f5)]
|
|
NativeMethods.OLECMDF QueryStatusWB([In] NativeMethods.OLECMDID cmdID);
|
|
[DispId(0x1f6)]
|
|
void ExecWB([In] NativeMethods.OLECMDID cmdID, [In] NativeMethods.OLECMDEXECOPT cmdexecopt, ref object pvaIn, IntPtr pvaOut);
|
|
[DispId(0x1f7)]
|
|
void ShowBrowserBar([In] ref object pvaClsid, [In] ref object pvarShow, [In] ref object pvarSize);
|
|
[DispId(-525)]
|
|
WebBrowserReadyState ReadyState { get; }
|
|
[DispId(550)]
|
|
bool Offline { get; set; }
|
|
[DispId(0x227)]
|
|
bool Silent { get; set; }
|
|
[DispId(0x228)]
|
|
bool RegisterAsBrowser { get; set; }
|
|
[DispId(0x229)]
|
|
bool RegisterAsDropTarget { get; set; }
|
|
[DispId(0x22a)]
|
|
bool TheaterMode { get; set; }
|
|
[DispId(0x22b)]
|
|
bool AddressBar { get; set; }
|
|
[DispId(0x22c)]
|
|
bool Resizable { get; set; }
|
|
}
|
|
|
|
}
|
|
}
|