diff --git a/NTwain/Data/TwainTypesExtended.cs b/NTwain/Data/TwainTypesExtended.cs
index e8b7389..1bb56da 100644
--- a/NTwain/Data/TwainTypesExtended.cs
+++ b/NTwain/Data/TwainTypesExtended.cs
@@ -1730,12 +1730,13 @@ namespace NTwain.Data
public string ProductName { get { return _productName; } set { value.VerifyLengthUnder(TwainConst.String32 - 1); _productName = value; } }
///
- /// Creates a from assembly values.
+ /// Creates a from assembly values.
///
/// The supported groups.
/// The assembly.
///
- /// assembly
+ /// assembly
+ ///
public static TWIdentity CreateFromAssembly(DataGroups supportedGroups, Assembly assembly)
{
if (assembly == null) { throw new ArgumentNullException("assembly"); }
@@ -1755,10 +1756,16 @@ namespace NTwain.Data
/// Name of the product.
/// The product description.
///
- /// version
+ /// assembly
+ ///
public static TWIdentity Create(DataGroups supportedGroups, Version version,
string manufacturer, string productFamily, string productName, string productDescription)
{
+ if ((supportedGroups & DataGroups.Image) == 0 &&
+ (supportedGroups & DataGroups.Audio) == 0)
+ {
+ throw new ArgumentException(Resources.BadDataGroupsForAppId);
+ }
if (version == null) { throw new ArgumentNullException("version"); }
return new TWIdentity
diff --git a/NTwain/DataTransferredEventArgs.cs b/NTwain/DataTransferredEventArgs.cs
index a6c3724..c447081 100644
--- a/NTwain/DataTransferredEventArgs.cs
+++ b/NTwain/DataTransferredEventArgs.cs
@@ -8,6 +8,37 @@ namespace NTwain
///
public class DataTransferredEventArgs : EventArgs
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The native data.
+ /// The image information.
+ public DataTransferredEventArgs(IntPtr nativeData, TWImageInfo imageInfo)
+ {
+ NativeData = nativeData;
+ ImageInfo = imageInfo;
+ }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The file data path.
+ /// The image information.
+ public DataTransferredEventArgs(string fileDataPath, TWImageInfo imageInfo)
+ {
+ FileDataPath = fileDataPath;
+ ImageInfo = imageInfo;
+ }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory data.
+ /// The image information.
+ public DataTransferredEventArgs(byte[] memoryData, TWImageInfo imageInfo)
+ {
+ MemoryData = memoryData;
+ ImageInfo = imageInfo;
+ }
+
///
/// Gets pointer to the complete data if the transfer was native.
/// The data will be freed once the event handler ends
@@ -16,7 +47,7 @@ namespace NTwain
/// This pointer is already locked for the duration of this event.
///
/// The data pointer.
- public IntPtr NativeData { get; internal set; }
+ public IntPtr NativeData { get; private set; }
///
/// Gets the file path to the complete data if the transfer was file or memory-file.
@@ -24,7 +55,7 @@ namespace NTwain
///
/// The file path.
///
- public string FileDataPath { get; internal set; }
+ public string FileDataPath { get; private set; }
///
/// Gets the raw memory data if the transfer was memory.
@@ -35,7 +66,7 @@ namespace NTwain
/// The memory data.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
- public byte[] MemoryData { get; internal set; }
+ public byte[] MemoryData { get; private set; }
///
/// Gets the final image information if applicable.
@@ -43,7 +74,7 @@ namespace NTwain
///
/// The final image information.
///
- public TWImageInfo ImageInfo { get; internal set; }
+ public TWImageInfo ImageInfo { get; private set; }
/////
///// Gets the extended image information if applicable.
diff --git a/NTwain/Internals/TransferLogic.cs b/NTwain/Internals/TransferLogic.cs
index 8ce7b62..562885c 100644
--- a/NTwain/Internals/TransferLogic.cs
+++ b/NTwain/Internals/TransferLogic.cs
@@ -39,14 +39,7 @@ namespace NTwain.Internals
}
// ask consumer for xfer details
- var preXferArgs = new TransferReadyEventArgs
- {
- AudioInfo = audInfo,
- PendingImageInfo = imgInfo,
- PendingTransferCount = pending.Count,
- EndOfJob = pending.EndOfJob == 0
- };
-
+ var preXferArgs = new TransferReadyEventArgs(pending.Count, pending.EndOfJob == 0, imgInfo, audInfo); ;
session.SafeSyncableRaiseEvent(preXferArgs);
#endregion
@@ -144,16 +137,16 @@ namespace NTwain.Internals
lockedPtr = Platform.MemoryManager.Lock(dataPtr);
}
- session.SafeSyncableRaiseEvent(new DataTransferredEventArgs { NativeData = lockedPtr });
+ session.SafeSyncableRaiseEvent(new DataTransferredEventArgs(lockedPtr, null));
}
else
{
- session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.CurrentSource.GetStatus() });
+ session.SafeSyncableRaiseEvent(new TransferErrorEventArgs(xrc, session.CurrentSource.GetStatus()));
}
}
catch (Exception ex)
{
- session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { Exception = ex });
+ session.SafeSyncableRaiseEvent(new TransferErrorEventArgs(ex));
}
finally
{
@@ -184,11 +177,11 @@ namespace NTwain.Internals
var xrc = session.DGAudio.AudioFileXfer.Get();
if (xrc == ReturnCode.XferDone)
{
- session.SafeSyncableRaiseEvent(new DataTransferredEventArgs { FileDataPath = filePath });
+ session.SafeSyncableRaiseEvent(new DataTransferredEventArgs(filePath, null));
}
else
{
- session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.CurrentSource.GetStatus() });
+ session.SafeSyncableRaiseEvent(new TransferErrorEventArgs(xrc, session.CurrentSource.GetStatus()));
}
}
@@ -214,12 +207,12 @@ namespace NTwain.Internals
}
else
{
- session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.CurrentSource.GetStatus() });
+ session.SafeSyncableRaiseEvent(new TransferErrorEventArgs(xrc, session.CurrentSource.GetStatus()));
}
}
catch (Exception ex)
{
- session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { Exception = ex });
+ session.SafeSyncableRaiseEvent(new TransferErrorEventArgs(ex));
}
finally
{
@@ -254,7 +247,7 @@ namespace NTwain.Internals
}
else
{
- session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.CurrentSource.GetStatus() });
+ session.SafeSyncableRaiseEvent(new TransferErrorEventArgs(xrc, session.CurrentSource.GetStatus()));
}
}
@@ -317,13 +310,13 @@ namespace NTwain.Internals
}
else
{
- session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.CurrentSource.GetStatus() });
+ session.SafeSyncableRaiseEvent(new TransferErrorEventArgs(xrc, session.CurrentSource.GetStatus()));
}
}
}
catch (Exception ex)
{
- session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { Exception = ex });
+ session.SafeSyncableRaiseEvent(new TransferErrorEventArgs(ex));
}
finally
{
@@ -396,12 +389,12 @@ namespace NTwain.Internals
}
else
{
- session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.CurrentSource.GetStatus() });
+ session.SafeSyncableRaiseEvent(new TransferErrorEventArgs(xrc, session.CurrentSource.GetStatus()));
}
}
catch (Exception ex)
{
- session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { Exception = ex });
+ session.SafeSyncableRaiseEvent(new TransferErrorEventArgs(ex));
}
finally
{
@@ -425,6 +418,7 @@ namespace NTwain.Internals
static void DoImageXferredEventRoutine(ITwainSessionInternal session, IntPtr dataPtr, byte[] dataArray, string filePath)
{
+ DataTransferredEventArgs args = null;
TWImageInfo imgInfo;
//TWExtImageInfo extInfo = null;
//if (session.CurrentSource.SupportedCaps.Contains(CapabilityId.ICapExtImageInfo))
@@ -438,14 +432,19 @@ namespace NTwain.Internals
{
imgInfo = null;
}
- session.SafeSyncableRaiseEvent(new DataTransferredEventArgs
+ if (dataPtr != IntPtr.Zero)
{
- NativeData = dataPtr,
- MemoryData = dataArray,
- FileDataPath = filePath,
- ImageInfo = imgInfo,
- //ExImageInfo = extInfo
- });
+ args = new DataTransferredEventArgs(dataPtr, imgInfo);
+ }
+ else if (dataArray != null)
+ {
+ args = new DataTransferredEventArgs(dataArray, imgInfo);
+ }
+ else
+ {
+ args = new DataTransferredEventArgs(filePath, imgInfo);
+ }
+ session.SafeSyncableRaiseEvent(args);
//if (extInfo != null) { extInfo.Dispose(); }
}
diff --git a/NTwain/MessageLoopHooks.cs b/NTwain/MessageLoopHooks.cs
index ee2bfe7..1e4a477 100644
--- a/NTwain/MessageLoopHooks.cs
+++ b/NTwain/MessageLoopHooks.cs
@@ -113,7 +113,6 @@ namespace NTwain
//{
System.Windows.Forms.Application.RemoveMessageFilter(this);
_filter = null;
- Handle = IntPtr.Zero;
//});
}
@@ -191,9 +190,9 @@ namespace NTwain
if (_hooker != null)
{
_hooker.RemoveHook(FilterMessage);
- _hooker.Dispose();
+ // cannot really dispose _hook or the window will also dispose
+ //_hooker.Dispose();
_hooker = null;
- Handle = IntPtr.Zero;
}
}
}
diff --git a/NTwain/Properties/Resources.Designer.cs b/NTwain/Properties/Resources.Designer.cs
index 7e7473b..5636576 100644
--- a/NTwain/Properties/Resources.Designer.cs
+++ b/NTwain/Properties/Resources.Designer.cs
@@ -8,10 +8,10 @@
//
//------------------------------------------------------------------------------
-namespace NTwain.Properties
-{
-
-
+namespace NTwain.Properties {
+ using System;
+
+
///
/// A strongly-typed resource class, for looking up localized strings, etc.
///
@@ -60,6 +60,15 @@ namespace NTwain.Properties
}
}
+ ///
+ /// Looks up a localized string similar to Data group for application must contain either Image or Audio..
+ ///
+ internal static string BadDataGroupsForAppId {
+ get {
+ return ResourceManager.GetString("BadDataGroupsForAppId", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Invalid value type for {0}..
///
diff --git a/NTwain/Properties/Resources.resx b/NTwain/Properties/Resources.resx
index 2f92336..a8b8d9f 100644
--- a/NTwain/Properties/Resources.resx
+++ b/NTwain/Properties/Resources.resx
@@ -112,11 +112,14 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ Data group for application must contain either Image or Audio.
+
Invalid value type for {0}.
diff --git a/NTwain/TransferErrorEventArgs.cs b/NTwain/TransferErrorEventArgs.cs
index 583e940..2ad4434 100644
--- a/NTwain/TransferErrorEventArgs.cs
+++ b/NTwain/TransferErrorEventArgs.cs
@@ -8,13 +8,33 @@ namespace NTwain
///
public class TransferErrorEventArgs : EventArgs
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The error.
+ public TransferErrorEventArgs(Exception error)
+ {
+ Exception = error;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The code.
+ /// The status.
+ public TransferErrorEventArgs(ReturnCode code, TWStatus status)
+ {
+ ReturnCode = code;
+ SourceStatus = status;
+ }
+
///
/// Gets the return code from the transfer.
///
///
/// The return code.
///
- public ReturnCode ReturnCode { get; internal set; }
+ public ReturnCode ReturnCode { get; private set; }
///
/// Gets the source status.
@@ -22,7 +42,7 @@ namespace NTwain
///
/// The source status.
///
- public TWStatus SourceStatus { get; internal set; }
+ public TWStatus SourceStatus { get; private set; }
///
/// Gets the exception if the error is from some exception.
@@ -30,6 +50,6 @@ namespace NTwain
///
/// The exception.
///
- public Exception Exception { get; internal set; }
+ public Exception Exception { get; private set; }
}
}
diff --git a/NTwain/TransferReadyEventArgs.cs b/NTwain/TransferReadyEventArgs.cs
index 1293fc4..6de97f4 100644
--- a/NTwain/TransferReadyEventArgs.cs
+++ b/NTwain/TransferReadyEventArgs.cs
@@ -8,6 +8,21 @@ namespace NTwain
///
public class TransferReadyEventArgs : EventArgs
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The pending count.
+ /// if set to true [end of job].
+ /// The image information.
+ /// The audio information.
+ public TransferReadyEventArgs(int pendingCount, bool endOfJob, TWImageInfo imageInfo, TWAudioInfo audioInfo)
+ {
+ PendingTransferCount = pendingCount;
+ EndOfJob = endOfJob;
+ PendingImageInfo = imageInfo;
+ AudioInfo = audioInfo;
+ }
+
///
/// Gets or sets a value indicating whether the current transfer should be canceled
/// and continue next transfer if there are more data.
@@ -25,14 +40,14 @@ namespace NTwain
/// Gets a value indicating whether current transfer signifies an end of job in TWAIN world.
///
/// true if transfer is end of job; otherwise, false.
- public bool EndOfJob { get; internal set; }
+ public bool EndOfJob { get; private set; }
///
/// Gets the known pending transfer count. This may not be appilicable
/// for certain scanning modes.
///
/// The pending count.
- public int PendingTransferCount { get; internal set; }
+ public int PendingTransferCount { get; private set; }
///
/// Gets the tentative image information for the current transfer if applicable.
@@ -41,7 +56,7 @@ namespace NTwain
///
/// The image info.
///
- public TWImageInfo PendingImageInfo { get; internal set; }
+ public TWImageInfo PendingImageInfo { get; private set; }
///
/// Gets the audio information for the current transfer if applicable.
@@ -49,7 +64,7 @@ namespace NTwain
///
/// The audio information.
///
- public TWAudioInfo AudioInfo { get; internal set; }
+ public TWAudioInfo AudioInfo { get; private set; }
}
}
diff --git a/NTwain/TwainSession.cs b/NTwain/TwainSession.cs
index f3061c2..2782993 100644
--- a/NTwain/TwainSession.cs
+++ b/NTwain/TwainSession.cs
@@ -18,7 +18,7 @@ namespace NTwain
///
/// Basic class for interfacing with TWAIN. You should only have one of this per application process.
///
- public partial class TwainSession : ITwainSessionInternal, IWinMessageFilter
+ public partial class TwainSession
{
///
/// Initializes a new instance of the class.
@@ -557,114 +557,5 @@ namespace NTwain
protected virtual void OnTransferError(TransferErrorEventArgs e) { }
#endregion
-
- #region handle twain ds message
-
-
- #region IWinMessageFilter Members
-
- ///
- /// Checks and handle the message if it's a TWAIN message.
- ///
- /// The window handle.
- /// The message.
- /// The w parameter.
- /// The l parameter.
- ///
- /// true if handled internally.
- ///
- public bool IsTwainMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam)
- {
- bool handled = false;
- // this handles the message from a typical WndProc message loop and check if it's from the TWAIN source.
- if (_state >= 5)
- {
- // transform it into a pointer for twain
- IntPtr msgPtr = IntPtr.Zero;
- try
- {
- var winMsg = new NTwain.Internals.MESSAGE(hwnd, msg, wParam, lParam);
-
- // no need to do another lock call when using marshal alloc
- msgPtr = Marshal.AllocHGlobal(Marshal.SizeOf(winMsg));
- Marshal.StructureToPtr(winMsg, msgPtr, false);
-
- var evt = new TWEvent();
- evt.pEvent = msgPtr;
- if (handled = (((ITwainSessionInternal)this).DGControl.Event.ProcessEvent(evt) == ReturnCode.DSEvent))
- {
- Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: HandleWndProcMessage at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, evt.TWMessage));
-
- HandleSourceMsg(evt.TWMessage);
- }
- }
- finally
- {
- if (msgPtr != IntPtr.Zero) { Marshal.FreeHGlobal(msgPtr); }
- }
- }
- return handled;
- }
-
- #endregion
-
- ReturnCode HandleCallback(TWIdentity origin, TWIdentity destination, DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
- {
- if (origin != null && CurrentSource != null && origin.Id == CurrentSource.Identity.Id && _state >= 5)
- {
- Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: CallbackHandler at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, msg));
- // spec says we must handle this on the thread that enabled the DS.
- // by using the internal dispatcher this will be the case.
-
- _msgLoopHook.BeginInvoke(() =>
- {
- HandleSourceMsg(msg);
- });
- return ReturnCode.Success;
- }
- return ReturnCode.Failure;
- }
-
- // final method that handles msg from the source, whether it's from wndproc or callbacks
- void HandleSourceMsg(Message msg)
- {
- switch (msg)
- {
- case Message.XferReady:
- if (State < 6)
- {
- State = 6;
- }
- TransferLogic.DoTransferRoutine(this);
- break;
- case Message.DeviceEvent:
- TWDeviceEvent de;
- var rc = ((ITwainSessionInternal)this).DGControl.DeviceEvent.Get(out de);
- if (rc == ReturnCode.Success)
- {
- SafeSyncableRaiseOnEvent(OnDeviceEvent, DeviceEvent, new DeviceEventArgs(de));
- }
- break;
- case Message.CloseDSReq:
- case Message.CloseDSOK:
- Debug.WriteLine("Got msg " + msg);
- // even though it says closeDS it's really disable.
- // dsok is sent if source is enabled with uionly
-
- // some sources send this at other states so do a step down
- if (State > 5)
- {
- ForceStepDown(4);
- }
- else if (State == 5)
- {
- // needs this state check since some source sends this more than once
- ((ITwainSessionInternal)this).DisableSource();
- }
- break;
- }
- }
-
- #endregion
}
}
diff --git a/NTwain/TwainSessionInternal.cs b/NTwain/TwainSessionInternal.cs
index 46115f9..5e3a4b2 100644
--- a/NTwain/TwainSessionInternal.cs
+++ b/NTwain/TwainSessionInternal.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
+using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
@@ -13,7 +14,7 @@ namespace NTwain
{
// for internal pieces since the main twain session file is getting too long
- partial class TwainSession
+ partial class TwainSession : ITwainSessionInternal, IWinMessageFilter
{
#region ITwainSessionInternal Members
@@ -196,5 +197,114 @@ namespace NTwain
#endregion
+ #region IWinMessageFilter Members
+
+ ///
+ /// Checks and handle the message if it's a TWAIN message.
+ ///
+ /// The window handle.
+ /// The message.
+ /// The w parameter.
+ /// The l parameter.
+ ///
+ /// true if handled internally.
+ ///
+ public bool IsTwainMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam)
+ {
+ bool handled = false;
+ // this handles the message from a typical WndProc message loop and check if it's from the TWAIN source.
+ if (_state >= 5)
+ {
+ // transform it into a pointer for twain
+ IntPtr msgPtr = IntPtr.Zero;
+ try
+ {
+ var winMsg = new NTwain.Internals.MESSAGE(hwnd, msg, wParam, lParam);
+
+ // no need to do another lock call when using marshal alloc
+ msgPtr = Marshal.AllocHGlobal(Marshal.SizeOf(winMsg));
+ Marshal.StructureToPtr(winMsg, msgPtr, false);
+
+ var evt = new TWEvent();
+ evt.pEvent = msgPtr;
+ if (handled = (((ITwainSessionInternal)this).DGControl.Event.ProcessEvent(evt) == ReturnCode.DSEvent))
+ {
+ Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: HandleWndProcMessage at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, evt.TWMessage));
+
+ HandleSourceMsg(evt.TWMessage);
+ }
+ }
+ finally
+ {
+ if (msgPtr != IntPtr.Zero) { Marshal.FreeHGlobal(msgPtr); }
+ }
+ }
+ return handled;
+ }
+
+ #endregion
+
+ #region handle twain ds message
+
+
+ ReturnCode HandleCallback(TWIdentity origin, TWIdentity destination, DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
+ {
+ if (origin != null && CurrentSource != null && origin.Id == CurrentSource.Identity.Id && _state >= 5)
+ {
+ Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: CallbackHandler at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, msg));
+ // spec says we must handle this on the thread that enabled the DS.
+ // by using the internal dispatcher this will be the case.
+
+ _msgLoopHook.BeginInvoke(() =>
+ {
+ HandleSourceMsg(msg);
+ });
+ return ReturnCode.Success;
+ }
+ return ReturnCode.Failure;
+ }
+
+ // final method that handles msg from the source, whether it's from wndproc or callbacks
+ void HandleSourceMsg(Message msg)
+ {
+ switch (msg)
+ {
+ case Message.XferReady:
+ if (State < 6)
+ {
+ State = 6;
+ }
+ TransferLogic.DoTransferRoutine(this);
+ break;
+ case Message.DeviceEvent:
+ TWDeviceEvent de;
+ var rc = ((ITwainSessionInternal)this).DGControl.DeviceEvent.Get(out de);
+ if (rc == ReturnCode.Success)
+ {
+ SafeSyncableRaiseOnEvent(OnDeviceEvent, DeviceEvent, new DeviceEventArgs(de));
+ }
+ break;
+ case Message.CloseDSReq:
+ case Message.CloseDSOK:
+ Debug.WriteLine("Got msg " + msg);
+ // even though it says closeDS it's really disable.
+ // dsok is sent if source is enabled with uionly
+
+ // some sources send this at other states so do a step down
+ if (State > 5)
+ {
+ ForceStepDown(4);
+ }
+ else if (State == 5)
+ {
+ // needs this state check since some source sends this more than once
+ ((ITwainSessionInternal)this).DisableSource();
+ }
+ break;
+ }
+ }
+
+ #endregion
+
}
}