Namespace TCP.Frame
    ''' <summary>
    ''' Classe de base pour les trames contenant des données
    ''' </summary>
    ''' <remarks></remarks>
    Friend MustInherit Class ClsFrameModbusWrittingWord
        Inherits ClsFrameModbusBase

        Implements IList(Of UShort)

        ''' <summary>
        ''' Copie de mémoire
        ''' </summary>
        ''' <param name="Destination">Mot</param>
        ''' <param name="Source">Tableau d'octet</param>
        ''' <param name="Length">Longueur de copie</param>
        ''' <remarks></remarks>
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Single, ByRef Source As Byte, ByVal Length As Long)
        ''' <summary>
        ''' Copie de mémoire
        ''' </summary>
        ''' <param name="Destination">Tableau d'octet</param>
        ''' <param name="Source">Mot</param>
        ''' <param name="Length">Longueur de copie</param>
        ''' <remarks></remarks>
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Byte, ByRef Source As Single, ByVal Length As Long)

        ''' <summary>
        ''' Collection de données
        ''' </summary>
        ''' <remarks></remarks>
        Private mDatas As New List(Of UShort)

#Region "Constructeurs"
        ''' <summary>
        ''' Constructeur de la classe
        ''' </summary>
        ''' <param name="pTransId">numéro de la transaction</param>
        ''' <param name="pSlaveId">Numéro d'esclave</param>
        ''' <param name="pFunction">Numéro de fonction</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal pTransId As UShort, ByVal pSlaveId As Byte, ByVal pFunction As Byte)
            MyBase.New(pTransId, pSlaveId, pFunction)
        End Sub
        ''' <summary>
        ''' Constructeur de la classe
        ''' </summary>
        ''' <param name="pTransId">numéro de la transaction</param>
        ''' <param name="pSlaveId">Numéro d'esclave</param>
        ''' <param name="pFunction">Numéro de fonction</param>
        ''' <param name="pData">Données à utiliser</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal pTransId As UShort, ByVal pSlaveId As Byte, ByVal pFunction As Byte, ByVal pData As UShort())
            MyClass.New(pTransId, pSlaveId, pFunction)
            mDatas.AddRange(pData)
        End Sub
        ''' <summary>
        ''' Constructeur de la classe
        ''' </summary>
        ''' <param name="pSlaveId">Numéro d'esclave</param>
        ''' <param name="pFunction">Numéro de fonction</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal pSlaveId As Byte, ByVal pFunction As Byte)
            MyBase.New(pSlaveId, pFunction)
        End Sub
        ''' <summary>
        ''' Constructeur de la classe
        ''' </summary>
        ''' <param name="pSlaveId">Numéro d'esclave</param>
        ''' <param name="pFunction">Numéro de fonction</param>
        ''' <param name="pData">Données à utiliser</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal pSlaveId As Byte, ByVal pFunction As Byte, ByVal pData As UShort())
            MyClass.New(pSlaveId, pFunction)
            mDatas.AddRange(pData)
        End Sub
        ''' <summary>
        ''' Constructeur de la classe
        ''' </summary>
        ''' <param name="pFrame1">Trame à traiter</param>
        ''' <param name="pFrame2">Trame à traiter (copie)</param>
        ''' <remarks></remarks>
        Public Sub New(ByRef pFrame1 As Byte(), ByVal pFrame2 As Byte())
            MyBase.New(pFrame1)
            mDatas.Clear()
            For i As Integer = 1 To pFrame1(LengthOffset) Step 2
                UInt8((i - 1) \ 2, False) = pFrame1(i - 1 + DataOffset)
                UInt8((i - 1) \ 2, True) = pFrame1(i - 1 + DataOffset + 1)
            Next
        End Sub
#End Region

#Region "Elements à substituer dans les classes filles"
        ''' <summary>
        ''' Définit l'offset au quel débute les données
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Protected Overridable ReadOnly Property DataOffset() As Integer
            Get
                Return LengthOffset + 1
            End Get
        End Property
        ''' <summary>
        ''' Définit l'offset auquel se trouve la longueur (en octet des données)
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Protected MustOverride ReadOnly Property LengthOffset() As Integer
#End Region

        ''' <summary>
        ''' Génère la trame ModBus pour les enfants
        ''' </summary>
        ''' <param name="ptByte1">Données avant les données</param>
        ''' <param name="ptByte2">Données après les données</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Protected Overloads Function GetFrame(ByVal ptByte1 As Byte(), ByVal ptByte2 As Byte()) As Byte()
            If Count >= 128 Then
                Throw New IncorrectFrameException("Trame de données avec trop de données (>127 mots)", New Byte() {})
            End If
            ' CByte(IIF(Count < 128, Count * 2, 255))
            Dim ltByte As New List(Of Byte)
            ltByte.AddRange(ptByte1)
            ltByte.Add(CByte(IIF(Count < 128, Count * 2, 0)))

            For i As Integer = 0 To Count - 1
                ltByte.Add(CByte((mDatas(i) And &HFF00) >> 8))
                ltByte.Add(CByte(mDatas(i) And &HFF))
            Next

            ltByte.AddRange(ptByte2)

            Return MyBase.GetFrame(ltByte.ToArray)
        End Function

#Region "Implémentation de IList(Of UShort)"
        ''' <summary>
        ''' Ajoute un mot à la fin des donnéers actuelles
        ''' </summary>
        ''' <param name="item">Element à ajouter</param>
        ''' <remarks></remarks>
        Public Sub Add(ByVal item As UShort) Implements System.Collections.Generic.ICollection(Of UShort).Add
            If mDatas.Count >= 127 Then
                Throw New ArgumentException("Trop de données dans le tableau")
            End If
            mDatas.Add(item)
        End Sub
        ''' <summary>
        ''' Vide les données
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Clear() Implements System.Collections.Generic.ICollection(Of UShort).Clear
            mDatas.Clear()
        End Sub
        ''' <summary>
        ''' Retourne un bouléne indiquant si le mot passé en paramètre est contenu dans les données
        ''' </summary>
        ''' <param name="item">Donnée à recherchée</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function Contains(ByVal item As UShort) As Boolean Implements System.Collections.Generic.ICollection(Of UShort).Contains
            Throw New NotImplementedException()
        End Function
        ''' <summary>
        ''' Copie les données
        ''' </summary>
        ''' <param name="array"></param>
        ''' <param name="arrayIndex"></param>
        ''' <remarks></remarks>
        Public Sub CopyTo(ByVal array() As UShort, ByVal arrayIndex As Integer) Implements System.Collections.Generic.ICollection(Of UShort).CopyTo
            mDatas.CopyTo(array, arrayIndex)
        End Sub
        ''' <summary>
        ''' Retourne le nombre de mots
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Count() As Integer Implements System.Collections.Generic.ICollection(Of UShort).Count
            Get
                Return mDatas.Count
            End Get
        End Property
        ''' <summary>
        ''' Retourne false
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property IsReadOnly() As Boolean Implements System.Collections.Generic.ICollection(Of UShort).IsReadOnly
            Get
                Return False
            End Get
        End Property
        ''' <summary>
        ''' Non implémenté
        ''' </summary>
        ''' <param name="item"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function Remove(ByVal item As UShort) As Boolean Implements System.Collections.Generic.ICollection(Of UShort).Remove
            Throw New NotImplementedException()
        End Function
        ''' <summary>
        ''' Retoruen l'énumérateur
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of UShort) Implements System.Collections.Generic.IEnumerable(Of UShort).GetEnumerator
            Return mDatas.GetEnumerator
        End Function
        ''' <summary>
        ''' Non implémenté
        ''' </summary>
        ''' <param name="item"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function IndexOf(ByVal item As UShort) As Integer Implements System.Collections.Generic.IList(Of UShort).IndexOf
            Throw New NotImplementedException()
        End Function
        ''' <summary>
        ''' Insert un mot
        ''' </summary>
        ''' <param name="index"></param>
        ''' <param name="item"></param>
        ''' <remarks></remarks>
        Public Sub Insert(ByVal index As Integer, ByVal item As UShort) Implements System.Collections.Generic.IList(Of UShort).Insert
            If mDatas.Count >= 127 Then
                Throw New ArgumentException("Trop de données dans le tableau")
            End If
            mDatas.Insert(index, item)
        End Sub
        ''' <summary>
        ''' Retourne ou définit un mot
        ''' </summary>
        ''' <param name="index"></param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Default Public Property Item(ByVal index As Integer) As UShort Implements System.Collections.Generic.IList(Of UShort).Item
            Get
                Return mDatas(index)
            End Get
            Set(ByVal value As UShort)
                mDatas(index) = value
            End Set
        End Property
        ''' <summary>
        ''' Supprime un mot
        ''' </summary>
        ''' <param name="index"></param>
        ''' <remarks></remarks>
        Public Sub RemoveAt(ByVal index As Integer) Implements System.Collections.Generic.IList(Of UShort).RemoveAt
            mDatas.RemoveAt(index)
        End Sub
        ''' <summary>
        ''' Retourne l'énumérateur
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
            Return mDatas.GetEnumerator
        End Function
#End Region

#Region "Gestion des données"

#Region "Propriétés"

#Region "Motorola"
        ''' <summary>
        ''' Retourne ou définit un entier non signé sur 32 bits (format Motorola)
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property [UInt32](ByVal pOffset As Integer) As UInteger
            Get
                If mDatas.Count < pOffset + 2 Then
                    Return 0
                Else
                    Return (CUInt(mDatas(pOffset)) << 16) + CUInt(mDatas(pOffset + 1))
                End If
            End Get
            Set(ByVal value As UInteger)
                If mDatas.Count < pOffset + 2 Then
                    AddZeros(pOffset + 1)
                End If
                mDatas(pOffset) = CUShort(value >> 16)
                mDatas(pOffset + 1) = CUShort(value And &HFFFF)
            End Set
        End Property
        ''' <summary>
        ''' Retourne ou définit une entier signé sur 32 bits (format Motorola)
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property [Int32](ByVal pOffset As Integer) As Integer
            Get
                Dim lUInt As UInteger = UInt32(pOffset)
                If lUInt > Integer.MaxValue Then
                    Return CInt(CLng(lUInt) - UInteger.MaxValue - 1)
                Else
                    Return CInt(lUInt)
                End If
            End Get
            Set(ByVal value As Integer)
                If value < 0 Then
                    UInt32(pOffset) = CUInt(CLng(value) + UInteger.MaxValue + 1)
                Else
                    UInt32(pOffset) = CUInt(value)
                End If
            End Set
        End Property
        ''' <summary>
        ''' Retourne ou définit un entier non signé sur 16 bits (format Motorola)
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property [UInt16](ByVal pOffset As Integer) As UShort
            Get
                If mDatas.Count <= pOffset Then
                    Return 0
                Else
                    Return mDatas(pOffset)
                End If
            End Get
            Set(ByVal value As UShort)
                If mDatas.Count <= pOffset Then
                    AddZeros(pOffset)
                End If
                mDatas(pOffset) = value
            End Set
        End Property
        ''' <summary>
        ''' Retourne ou définit un entier signé sur 16 bits (format Motorola)
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property [Int16](ByVal pOffset As Integer) As Short
            Get
                Dim lInt As Integer = CInt(UInt16(pOffset))
                If lInt > Short.MaxValue Then
                    Return CShort(lInt - UShort.MaxValue - 1)
                Else
                    Return CShort(lInt)
                End If
            End Get
            Set(ByVal value As Short)
                If value < 0 Then
                    UInt16(pOffset) = CUShort(CInt(value) + UShort.MaxValue + 1)
                Else
                    UInt16(pOffset) = CUShort(value)
                End If
            End Set
        End Property
        ''' <summary>
        ''' Retourne ou définit un octet non signé
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <param name="pLSB">Indique s'il s'agit de l'octet de poids faible du mot</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property UInt8(ByVal pOffset As Integer, ByVal pLSB As Boolean) As Byte
            Get
                Dim lUShort As UShort = UInt16(pOffset)
                If pLSB Then
                    Return CByte(lUShort And &HFF)
                Else
                    Return CByte((lUShort And &HFF00) >> 8)
                End If
            End Get
            Set(ByVal value As Byte)
                Dim lUShort As UShort = UInt16(pOffset)
                If pLSB Then
                    lUShort = CUShort((lUShort And &HFF00) Or value)
                Else
                    lUShort = CUShort((lUShort And &HFF) Or (CUShort(value) << 8))
                End If
                UInt16(pOffset) = lUShort
            End Set
        End Property
        ''' <summary>
        ''' Retour ou définit un octet signé
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <param name="pLSB">Indique s'il s'agit de l'octet de poids faible du mot</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Int8(ByVal pOffset As Integer, ByVal pLSB As Boolean) As SByte
            Get
                Dim lInt As Integer = CInt(UInt8(pOffset, pLSB))
                If lInt > SByte.MaxValue Then
                    Return CSByte(lInt - Byte.MaxValue - 1)
                Else
                    Return CSByte(lInt)
                End If
            End Get
            Set(ByVal value As SByte)
                If value < 0 Then
                    Dim lInt As Integer = value
                    UInt8(pOffset, pLSB) = CByte(lInt + Byte.MaxValue + 1)
                Else
                    UInt8(pOffset, pLSB) = CByte(value)
                End If
            End Set
        End Property
        ''' <summary>
        ''' Retourne ou définit une chaine de caractère (premier à gauche)
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <param name="pLength">Longueur à lire/écrire (optionnel en écriture)</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property [String](ByVal pOffset As Integer, ByVal pLength As Integer) As String
            Get
                Dim lUShort As UShort
                Dim lStr As String = ""

                Do While pLength > 0
                    lUShort = UInt16(pOffset)
                    pOffset += 1

                    pLength -= 1
                    lStr += Chr(lUShort >> 8)

                    If pLength > 0 Then
                        pLength -= 1
                        lStr += Chr(lUShort And &HFF)
                    End If
                Loop

                Return lStr
            End Get
            Set(ByVal value As String)
                If pLength <= 0 Then
                    pLength = value.Length
                ElseIf pLength > value.Length Then
                    Do While pLength > value.Length
                        value += " "
                    Loop
                End If

                value = value.Substring(0, pLength)

                Do While value.Length > 1
                    UInt16(pOffset) = CUShort(((Asc(value.Substring(0, 1))) << 8) Or (Asc(value.Substring(1, 1))))
                    value = value.Substring(2)
                    pOffset += 1
                Loop

                If value.Length > 0 Then
                    UInt8(pOffset, False) = CByte(value)
                End If
            End Set
        End Property
        ''' <summary>
        ''' Définit une chaine de caractère (premier à gauche)
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <value></value>
        ''' <remarks></remarks>
        Public WriteOnly Property [String](ByVal pOffset As Integer) As String
            Set(ByVal value As String)
                Me.String(pOffset, value.Length) = value
            End Set
        End Property
        ''' <summary>
        ''' Retourne ou définit un bit d'un mot (format Motorola)
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <param name="pNumBit">Numéro du bit (0 LSB, valeur entre 0 et 15 bornes comprises)</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property [Boolean](ByVal pOffset As Integer, ByVal pNumBit As Integer) As Boolean
            Get
                If pNumBit < 0 Or pNumBit > 15 Then
                    Throw New ArgumentException("pNumBit doit être compris entre 0 et 15 (borne incluses)", "pNumBit")
                End If

                Dim lUShort As UShort = UInt16(pOffset)
                Return (lUShort And (1 << pNumBit)) <> 0
            End Get
            Set(ByVal value As Boolean)
                If pNumBit < 0 Or pNumBit > 7 Then
                    Throw New ArgumentException("pNumBit doit être compris entre 0 et 7 (borne incluses)", "pNumBit")
                End If

                Dim lUShort As UShort = UInt16(pOffset)
                If value Then
                    lUShort = CUShort(lUShort Or (1 << pNumBit))
                Else
                    lUShort = CUShort(lUShort And Not (1 << pNumBit))
                End If
                UInt16(pOffset) = lUShort
            End Set
        End Property
#End Region

#Region "Intel"
        ''' <summary>
        ''' Retourne ou définit un entier non signé sur 32 bits (format Intel)
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property IntelUInt32(ByVal pOffset As Integer) As UInteger
            Get
                If mDatas.Count < pOffset + 2 Then
                    Return 0
                Else
                    Return CUInt(mDatas(pOffset)) + (CUInt(mDatas(pOffset + 1)) << 16)
                End If
            End Get
            Set(ByVal value As UInteger)
                If mDatas.Count < pOffset + 2 Then
                    AddZeros(pOffset + 1)
                End If
                mDatas(pOffset + 1) = CUShort(value >> 16)
                mDatas(pOffset) = CUShort(value And &HFFFF)
            End Set
        End Property
        ''' <summary>
        ''' Retourne ou définit une entier signé sur 32 bits (format Intel)
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property IntelInt32(ByVal pOffset As Integer) As Integer
            Get
                Dim lUInt As UInteger = IntelUInt32(pOffset)
                If lUInt > Integer.MaxValue Then
                    Return CInt(CLng(lUInt) - UInteger.MaxValue - 1)
                Else
                    Return CInt(lUInt)
                End If
            End Get
            Set(ByVal value As Integer)
                If value < 0 Then
                    IntelUInt32(pOffset) = CUInt(CLng(value) + UInteger.MaxValue + 1)
                Else
                    IntelUInt32(pOffset) = CUInt(value)
                End If
            End Set
        End Property
        ''' <summary>
        ''' Retourne ou définit une entier flottant simple précision
        ''' </summary>
        ''' <param name="pOffset">Décalage du mot par rapport à l'offset de base</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Float(ByVal pOffset As Integer) As Single
            Get
                Dim lSng As Single = 0
                Dim ltByte As Byte() = New Byte() {UInt8(pOffset + 1, True), UInt8(pOffset + 1, False), UInt8(pOffset, True), UInt8(pOffset, False)}
                CopyMemory(lSng, ltByte(0), 4)
                Return lSng
            End Get
            Set(ByVal value As Single)
                Dim ltByte(3) As Byte
                CopyMemory(ltByte(0), value, 4)
                UInt8(pOffset, False) = ltByte(3)
                UInt8(pOffset, True) = ltByte(2)
                UInt8(pOffset + 1, False) = ltByte(1)
                UInt8(pOffset + 1, True) = ltByte(0)
            End Set
        End Property
#End Region

#End Region

#Region "Procédures"
        ''' <summary>
        ''' Ajoute des zéros pour atteindre l'offset précisé
        ''' </summary>
        ''' <param name="pOffsetDestination">Offset à atteindre</param>
        ''' <remarks></remarks>
        Public Sub AddZeros(ByVal pOffsetDestination As Integer)
            AddValues(pOffsetDestination, 0)
        End Sub
        ''' <summary>
        ''' Met à zéro les mots
        ''' </summary>
        ''' <param name="pStart">Offset relatif de départ</param>
        ''' <param name="pLength">Longueur des données à définir</param>
        ''' <remarks></remarks>
        Public Sub SetZeros(ByVal pStart As Integer, ByVal pLength As Integer)
            SetValues(pStart, pLength, 0)
        End Sub
        ''' <summary>
        ''' Met à zéro depuis pStart à la fin des données actuellement présente
        ''' </summary>
        ''' <param name="pStart">Offset relatif de départ</param>
        ''' <remarks></remarks>
        Public Sub SetZeros(ByVal pStart As Integer)
            SetValues(pStart, 0)
        End Sub
        ''' <summary>
        ''' Ajoute pValue pour atteindre l'offset précisé
        ''' </summary>
        ''' <param name="pOffsetDestination">Offset à atteindre</param>
        ''' <param name="pValue">Valeur à utiliser</param>
        ''' <remarks></remarks>
        Public Sub AddValues(ByVal pOffsetDestination As Integer, ByVal pValue As UShort)
            Do While mDatas.Count <= pOffsetDestination
                mDatas.Add(pValue)
            Loop
        End Sub
        ''' <summary>
        ''' Met à pValue les mots
        ''' </summary>
        ''' <param name="pStart">Offset relatif de départ</param>
        ''' <param name="pLength">Longueur des données à définir</param>
        ''' <param name="pValue">Valeur à utiliser</param>
        ''' <remarks></remarks>
        Public Sub SetValues(ByVal pStart As Integer, ByVal pLength As Integer, ByVal pValue As UShort)
            For i As Integer = pStart To pStart + pLength - 1
                If i > (mDatas.Count - 1) Then Exit Sub
                mDatas(i) = pValue
            Next
        End Sub
        ''' <summary>
        ''' Met à pValue depuis pStart à la fin des données actuellement présente
        ''' </summary>
        ''' <param name="pStart">Offset relatif de départ</param>
        ''' <param name="pValue">Valeur à utiliser</param>
        ''' <remarks></remarks>
        Public Sub SetValues(ByVal pStart As Integer, ByVal pValue As UShort)
            SetValues(pStart, mDatas.Count - pStart, pValue)
        End Sub
#End Region

#End Region
    End Class
End Namespace