• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 334
  • Last Modified:

Help with comparing two xml files and create new xml file with unmatched records

Hi,

How do Icompare two xml files and create a list with data where the records don't match/

For example if I LinkFile1.xml includes;

<Table1>
<ID>1</ID>
<ctry>BEL</ctry>
<Item>BMW</ITEM>
<Loc>JSS</Loc>
</Table1>
<Table1>
<ID>2</ID>
<ctry>BEL</ctry>
<Item>HON</ITEM>
<Loc>JSS</Loc>
</Table1>

and LinkFile2 contains

<Table1>
<ID>1</ID>
<ctry>BEL</ctry>
<Item>BMW</ITEM>
<Loc>JSS</Loc>
</Table1>
<Table1>
<ID>2</ID>
<ctry>BEL</ctry>
<Item>HON</ITEM>
<Loc>NAS</Loc>
</Table1>
<Table1>
<ID>3</ID>
<ctry>BEL</ctry>
<Item>TOY</ITEM>
<Loc>JSS</Loc>
</Table1>

I need to create another xml file containing the data below because they don't match with LinkFile1.xml

<Table1>
<ID>2</ID>
<ctry>BEL</ctry>
<Item>HON</ITEM>
<Loc>NAS</Loc>
</Table1>
<Table1>
<ID>3</ID>
<ctry>BEL</ctry>
<Item>TOY</ITEM>
<Loc>JSS</Loc>
</Table1>

Thanks,

Victor
0
vcharles
Asked:
vcharles
  • 16
  • 11
1 Solution
 
Fernando SotoCommented:
Hi Victor;

The XML sample documents you have posted are NOT well formed because it has multiple Root nodes. Is it OK to rap the XML documents with <Root> .... </Root> ? for example

<Root>
    <Table1>
        <ID>1</ID>
        <ctry>BEL</ctry>
        <Item>BMW</ITEM>
        <Loc>JSS</Loc>
    </Table1>
    <Table1>
       <ID>2</ID>
       <ctry>BEL</ctry>
       <Item>HON</ITEM>
       <Loc>JSS</Loc>
    </Table1>
</Root>

Open in new window

0
 
vcharlesAuthor Commented:
Hi,

Yes, I forgot to include them.

Thanks,

Victor
0
 
Fernando SotoCommented:
Hi Victor;

Sorry I should have ask you also what happens where a node with a specific ID is in the first XML document but NOT in the second one?

 Also will each XML segment such as the following one :

<Table1>
    <ID>3</ID>
    <ctry>BEL</ctry>
    <Item>TOY</ITEM>
    <Loc>JSS</Loc>
</Table1>

Open in new window

Always have Table1 node with four child nodes always in the same order, for example ID, ctry, Item and Loc?
0
NEW Veeam Agent for Microsoft Windows

Backup and recover physical and cloud-based servers and workstations, as well as endpoint devices that belong to remote users. Avoid downtime and data loss quickly and easily for Windows-based physical or public cloud-based workloads!

 
vcharlesAuthor Commented:
Hi,


Yes, both files will have the same table name and data elements.

I'm trying to compare and old file with new file received, both files will have the same data elements but the new file may have changes from the old file or new records. I would like to create a new file for new records or changes to data in the old file.

Thanks,

Victor
0
 
Fernando SotoCommented:
Hi Victor;

The following code snippet should do what you need as stated in the question.

' First XML fie
Dim xdoc1 As XDocument = XDocument.Load("C:\Working Directory\linkfile1.xml")
' Second XML file
Dim xdoc2 As XDocument = XDocument.Load("C:\Working Directory\linkfile2.xml")
' The new XML file
Dim xdoc3 As New XDocument(New XElement("Root"))
' Get a list of all the main nodes
Dim rowsF1 = From t In xdoc1.Root.Elements("Table1")
             Select t

' Go through all the Table1 nodes from file1
For Each t As XElement In rowsF1
    ' Get its ID node
    Dim id1 As XElement = t.Element("ID")
    If id1 IsNot Nothing then
        ' Find the same node in XML file2
        Dim id2 As XElement = xdoc2.Root.Descendants("ID").Where(Function(i) i.Value = id1).FirstOrDefault()
        ' Check to see if file2 has this ID 
        If id2 IsNot Nothing
            ' Get all the individual values from both nodes
            Dim ctry1 As String = id1.Parent.Element("ctry").Value
            Dim item1 As String = id1.Parent.Element("Item").Value
            Dim loc1 As String = id1.Parent.Element("Loc").Value
            Dim ctry2 As String = id2.Parent.Element("ctry").Value
            Dim item2 As String = id2.Parent.Element("Item").Value
            Dim loc2 As String = id2.Parent.Element("Loc").Value
            ' Compare all like values for equality
            If ctry1.Equals(ctry2) AndAlso item1.Equals(item2) AndAlso loc1.Equals(loc2) Then
                ' Nothing needs to be done because the two nodes are the same
            Else
                ' The node from file1 does NOT match the node from file2 add it to the new document
                xdoc3.Root.Add(id2.Parent)
            End If
        Else
            ' The node in file1 was not found in file2 add this to the new XML file
            xdoc3.Root.Add(id1.Parent)
        End If
    End If
Next

' Get a list of all the Nodes that are in fil2 but not in file1 
Dim notInFirst As List(of XElement) = (From id in xdoc2.Root.Descendants("ID")
                                       Where Not xdoc1.Root.Descendants("ID").Any(Function(i) i.Value = id.Value)
                                       Select id).ToList()

' Add all the nodes in the list to the new XML file
If notInFirst.Count() > 0 Then
    For Each node As XElement In notInFirst
        xdoc3.Root.Add(node.Parent)
    Next
End If

' Save the document to the file system, change the path location
xdoc3.Save("C:\Working Directory\NewXMLFile.xml")

Open in new window

0
 
vcharlesAuthor Commented:
Thank You, will get back to you.
0
 
vcharlesAuthor Commented:
It works.

Thank You.

Victor
0
 
Fernando SotoCommented:
Not a problem Victor, glad I was able to help.
0
 
vcharlesAuthor Commented:
Hi again,

I just realized I didn't take into consideration multiple tables in the xml files, how would you modify the code to create a new file with multiple tables where data in LinkFile2 does not match LinkFile1? For example if LinkFile1.xml and LinkFile2.xml contained multiple tables?


LinkFile1.xml:

<Root>
    <Table1>
        <ID>1</ID>
        <ctry>BEL</ctry>
        <Item>BMW</ITEM>
        <Loc>JSS</Loc>
    </Table1>
    <Table1>
       <ID>2</ID>
       <ctry>BEL</ctry>
       <Item>HON</ITEM>
       <Loc>JSS</Loc>
    </Table1>
 <Table2>
       <ID>1</ID>
       <NSS>WHT</NSS>
       <NASC>HON</NASC>
       <FIF>JSS</FIF>
    </Table2>
 <Table3>
       <ID>1</ID>
       <EMD>YLL</EMD>
       <CUN>HON</CUN>
       <NMN>JSS</NMN>
    </Table3>
</Root>

LinkFile2.xml

<Root>
    <Table1>
        <ID>1</ID>
        <ctry>BEL</ctry>
        <Item>BMW</ITEM>
        <Loc>JSS</Loc>
    </Table1>
    <Table1>
       <ID>2</ID>
       <ctry>BEL</ctry>
       <Item>HON</ITEM>
       <Loc>JSS</Loc>
    </Table1>
 <Table2>
       <ID>1</ID>
       <NSS>GREEN</NSS>
       <NASC>HON</NASC>
       <FIF>JSS</FIF>
    </Table2>
 <Table3>
       <ID>1</ID>
       <EMD>Red</EMD>
       <CUN>yes</CUN>
       <NMN>JSS</NMN>
    </Table3>
</Root>

Thanks,

Victor
0
 
vcharlesAuthor Commented:
Hi,

I can use the same code and change the table names in the code below, but not certain if that's the best approach.

Dim rowsF1 = From t In xdoc1.Root.Elements("Table1")

because I would be creating an new xml file for each table when there is a difference between both files.

Thanks,

Victor
0
 
Fernando SotoCommented:
Hi Victor;

I am currently unable to give you an answer to your followup question. The solution you posted should work but let me give it a good look later on.
0
 
vcharlesAuthor Commented:
Thank you for letting me know, I hope to use a shorter/smarter approach.
0
 
Fernando SotoCommented:
Hi Victor;

Give this a try and see if it gives the needed results.

' First XML fie
Dim xdoc1 As XDocument = XDocument.Load("C:\Working Directory\linkfile1.xml")
' Second XML file
Dim xdoc2 As XDocument = XDocument.Load("C:\Working Directory\linkfile2.xml")
' The new XML file
Dim xdoc3 As New XDocument(New XElement("Root"))
' Get a list of all the main nodes, Table1, Table2, ....
Dim rowsF1 = From t In xdoc1.Root.Elements() _
             Select t

' Loop through all the nodes in file 1 and process
For Each node1 As XElement In rowsF1
    ' Get the Table name of the node
    Dim nodeName1 As String = node1.Name.ToString()
    ' Find that same element in File 2
    Dim findNode As XElement = (From t In xdoc2.Root.Elements() _
                                Where t.Name.ToString().Equals(nodeName1) AndAlso t.Element("ID").Value = node1.Element("ID").Value _
                                Select t).FirstOrDefault()
    ' If the node was found lets process it                            
    If findNode IsNot Nothing Then
        ' A test to find out which node gets added to the new File 3
        Dim addToNew As Boolean = True
        ' Match the nodes from file 1 with file 2
        For Each child In node1.Elements()
            Dim foundChild As XElement = findNode.Elements().Where(Function(t) t.Name = child.Name).FirstOrDefault()
            If foundChild IsNot Nothing Then
                If child.Value = foundChild.Value
                    ' Node name and value were the same process next node
                    Continue For
                Else
                    ' Not the same add node from file 2 to file 3
                    addToNew = False
                    xdoc3.Root.Add(findNode)
                    Exit For
                End If
            End If
        Next
        If addToNew Then
           xdoc3.Root.Add(node1)
       End If
    End If
Next

Open in new window

0
 
vcharlesAuthor Commented:
Thank you. I will let you know.
0
 
vcharlesAuthor Commented:
Hi,

I'm getting error message:

Object reference not set to an instance of an object.

On line:

 Where t.Name.ToString().Equals(nodeName1) AndAlso t.Element("ID").Value = node1.Element("ID").Value _
Select t).FirstOrDefault()


Code:
    Private Sub Button36_Click(sender As System.Object, e As System.EventArgs) Handles Button36.Click
        ' First XML fie
        Dim xdoc1 As XDocument = XDocument.Load(Application.StartupPath + "\Data\LinkFiles\LinkFinalA.xml")
        ' Second XML file
        Dim xdoc2 As XDocument = XDocument.Load(Application.StartupPath + "\Data\LinkFiles\LinkFinalB.xml")

        ' The new XML file
        Dim xdoc3 As New XDocument(New XElement("Root"))
        ' Get a list of all the main nodes, Table1, Table2, ....
        Dim rowsF1 = From t In xdoc1.Root.Elements() _
                     Select t

        ' Loop through all the nodes in file 1 and process
        For Each node1 As XElement In rowsF1
            ' Get the Table name of the node
            Dim nodeName1 As String = node1.Name.ToString()
            ' Find that same element in File 2
            Dim findNode As XElement = (From t In xdoc2.Root.Elements() _
                                        Where t.Name.ToString().Equals(nodeName1) AndAlso t.Element("ID").Value = node1.Element("ID").Value _
                                        Select t).FirstOrDefault()
            ' If the node was found lets process it                            
            If findNode IsNot Nothing Then
                ' A test to find out which node gets added to the new File 3
                Dim addToNew As Boolean = True
                ' Match the nodes from file 1 with file 2
                For Each child In node1.Elements()
                    Dim foundChild As XElement = findNode.Elements().Where(Function(t) t.Name = child.Name).FirstOrDefault()
                    If foundChild IsNot Nothing Then
                        If child.Value = foundChild.Value Then
                            ' Node name and value were the same process next node
                            Continue For
                        Else
                            ' Not the same add node from file 2 to file 3
                            addToNew = False
                            xdoc3.Root.Add(findNode)
                            Exit For
                        End If
                    End If
                Next
                If addToNew Then
                    xdoc3.Root.Add(node1)
                End If
            End If
        Next
        ' Get a list of all the Nodes that are in fil2 but not in file1
        Dim notInFirst As List(Of XElement) = (From id In xdoc2.Root.Descendants("Link_ID")
                                               Where Not xdoc1.Root.Descendants("Link_ID").Any(Function(i) i.Value = id.Value)
                                               Select id).ToList()

        ' Add all the nodes in the list to the new XML file
        If notInFirst.Count() > 0 Then
            For Each node As XElement In notInFirst
                xdoc3.Root.Add(node.Parent)
            Next
        End If

        ' Save the document to the file system, change the path location
        xdoc3.Save(Application.StartupPath + "\Data\LinkFiles\DiffFileddd.xml")
        Form6.Visible = True
    End Sub

Thanks,

Victor
0
 
vcharlesAuthor Commented:
Hi,

I think the error is with node1, it is underlined with a green line.

node1.Element("ID").Value
0
 
Fernando SotoCommented:
The Last code I posted should replace ALL the code from the post before that. You mixed both solutions together. Try just the code from my last post.
0
 
vcharlesAuthor Commented:
Hi,

The error was because my file contains link_ID instead of ID, I added the bottom part of the code to create the xml file if there is a mismatch, but the file created contains all the records in LinkFileB, Below are also the xml files I'm using. My third file ahould only contain record in LinkFileB for table Row1.  

Private Sub Button36_Click(sender As System.Object, e As System.EventArgs) Handles Button36.Click
        ' First XML fie
        Dim xdoc1 As XDocument = XDocument.Load(Application.StartupPath + "\Data\LinkFiles\LinkFinalA.xml")
        ' Second XML file
        Dim xdoc2 As XDocument = XDocument.Load(Application.StartupPath + "\Data\LinkFiles\LinkFinalB.xml")
        ' The new XML file
        Dim xdoc3 As New XDocument(New XElement("Root"))
        ' Get a list of all the main nodes, Table1, Table2, ....
        Dim rowsF1 = From t In xdoc1.Root.Elements() _
                     Select t

        ' Loop through all the nodes in file 1 and process
        For Each node1 As XElement In rowsF1
            ' Get the Table name of the node
            Dim nodeName1 As String = node1.Name.ToString()
            ' Find that same element in File 2
            Dim findNode As XElement = (From t In xdoc2.Root.Elements() _
                                        Where t.Name.ToString().Equals(nodeName1) AndAlso t.Element("Link_ID").Value = node1.Element("Link_ID").Value _
                                        Select t).FirstOrDefault()
            ' If the node was found lets process it                            
            If findNode IsNot Nothing Then
                ' A test to find out which node gets added to the new File 3
                Dim addToNew As Boolean = True
                ' Match the nodes from file 1 with file 2
                For Each child In node1.Elements()
                    Dim foundChild As XElement = findNode.Elements().Where(Function(t) t.Name = child.Name).FirstOrDefault()
                    If foundChild IsNot Nothing Then
                        If child.Value = foundChild.Value Then
                            ' Node name and value were the same process next node
                            Continue For
                        Else
                            ' Not the same add node from file 2 to file 3
                            addToNew = False
                            xdoc3.Root.Add(findNode)
                            Exit For
                        End If
                    End If
                Next
                If addToNew Then
                    xdoc3.Root.Add(node1)
                End If
            End If
        Next

'************************************************************

        ' Get a list of all the Nodes that are in fil2 but not in file1
        Dim notInFirst As List(Of XElement) = (From id In xdoc2.Root.Descendants("ID")
                                               Where Not xdoc1.Root.Descendants("ID").Any(Function(i) i.Value = id.Value)
                                               Select id).ToList()

        ' Add all the nodes in the list to the new XML file
        If notInFirst.Count() > 0 Then
            For Each node As XElement In notInFirst
                xdoc3.Root.Add(node.Parent)
            Next
        End If

        ' Save the document to the file system, change the path location
        xdoc3.Save(Application.StartupPath + "\Data\LinkFiles\LinkFinalSSS.xml")


XML files:

LinkFileAxml

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Row>
    <Link_ID>1</Link_ID>
    <Column1>2</Column1>
    <Column2>3</Column2>
    <Column3>4</Column3>
    <Column4>6</Column4>
  </Row>
  <Row1>
    <Link_ID>1</Link_ID>
    <Column1>33</Column1>
  </Row1>
</Root>


LinkFinalBxml

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Row>
    <Link_ID>1</Link_ID>
    <Column1>2</Column1>
    <Column2>3</Column2>
    <Column3>4</Column3>
    <Column4>6</Column4>
  </Row>
  <Row1>
    <Link_ID>1</Link_ID>
    <Column1>334</Column1>
  </Row1>
</Root>
0
 
vcharlesAuthor Commented:
Hi,

I'm using your latest code but still getting all the records in LinkFinalB.xml instead of just record for <Row1> any ideas why it's not working?


 Private Sub Button36_Click(sender As System.Object, e As System.EventArgs) Handles Button36.Click
        ' First XML fie
        Dim xdoc1 As XDocument = XDocument.Load(Application.StartupPath + "\Data\LinkFiles\LinkFinalA.xml")
        ' Second XML file
        Dim xdoc2 As XDocument = XDocument.Load(Application.StartupPath + "\Data\LinkFiles\LinkFinalB.xml")
        ' The new XML file
        Dim xdoc3 As New XDocument(New XElement("Root"))
        ' Get a list of all the main nodes, Table1, Table2, ....
        Dim rowsF1 = From t In xdoc1.Root.Elements() _
                     Select t

        ' Loop through all the nodes in file 1 and process
        For Each node1 As XElement In rowsF1
            ' Get the Table name of the node
            Dim nodeName1 As String = node1.Name.ToString()
            ' Find that same element in File 2
            Dim findNode As XElement = (From t In xdoc2.Root.Elements() _
                                        Where t.Name.ToString().Equals(nodeName1) AndAlso t.Element("Link_ID").Value = node1.Element("Link_ID").Value _
                                        Select t).FirstOrDefault()
            ' If the node was found lets process it                            
            If findNode IsNot Nothing Then
                ' A test to find out which node gets added to the new File 3
                Dim addToNew As Boolean = True
                ' Match the nodes from file 1 with file 2
                For Each child In node1.Elements()
                    Dim foundChild As XElement = findNode.Elements().Where(Function(t) t.Name = child.Name).FirstOrDefault()
                    If foundChild IsNot Nothing Then
                        If child.Value = foundChild.Value Then
                            ' Node name and value were the same process next node
                            Continue For
                        Else
                            ' Not the same add node from file 2 to file 3
                            addToNew = False
                            xdoc3.Root.Add(findNode)
                            Exit For
                        End If
                    End If
                Next
                If addToNew Then
                    xdoc3.Root.Add(node1)
                End If
            End If
        Next


' Code added to your code to view the third file
        xdoc3.Save(Application.StartupPath + "\Data\LinkFiles\LinkFinalC.xml")

Thanks,

Victor
0
 
Fernando SotoCommented:
Hi Victor;

Can you post the two XML files that you are using to test with so I can run and get the same results.

Also when posting code on a post use the Code image button in the toolbar to place

Code delimiters for post
It make it much easier to read and copy and paste when needed.
0
 
vcharlesAuthor Commented:
Hi Fernando,

Enclosed are the xml files.

Thanks,

Victor
LinkFinalA.xml
LinkFinalB.xml
0
 
Fernando SotoCommented:
Hi Victor;

Try this modified code.

' First XML fie
Dim xdoc1 As XDocument = XDocument.Load("C:\Working Directory\LinkFinalA.xml")
' Second XML file
Dim xdoc2 As XDocument = XDocument.Load("C:\Working Directory\LinkFinalB.xml")
' The new XML file
Dim xdoc3 As New XDocument(New XElement("Root"))
' Get a list of all the main nodes, Table1, Table2, ....
Dim rowsF1 = From t In xdoc1.Root.Elements() _
             Select t

' Loop through all the nodes in file 1 and process
For Each node1 As XElement In rowsF1
    ' Get the Table name of the node
    Dim nodeName1 As String = node1.Name.ToString()
    ' Find that same element in File 2
    Dim findNode As XElement = (From t In xdoc2.Root.Elements() _
                                Where t.Name.ToString().Equals(nodeName1) AndAlso t.Element("Link_ID").Value = node1.Element("Link_ID").Value _
                                Select t).FirstOrDefault()
    ' If the node was found lets process it                            
    If findNode IsNot Nothing Then
        ' A test to find out which node gets added to the new File 3
        Dim addToNew As Boolean = True
        ' Match the nodes from file 1 with file 2
        For Each child In node1.Elements()
            Dim foundChild As XElement = findNode.Elements().Where(Function(t) t.Name = child.Name).FirstOrDefault()
            If foundChild IsNot Nothing Then
                If child.Value = foundChild.Value Then
                    ' Node name and value were the same process next node
                    addToNew = False
                    Continue For
                Else
                    ' Not the same add node from file 2 to file 3
                    addToNew = True
                    Exit For
                End If
            End If
        Next
        If addToNew Then
            xdoc3.Root.Add(findNode)
        End If
    End If
Next

Open in new window

0
 
vcharlesAuthor Commented:
Thanks.  Will try it as soon as I get home and get back to you.
0
 
vcharlesAuthor Commented:
Hi,

It's working but only when the Link_ID in LinkFile A matches the Link_ID in LinkFileB, but if users enter a new record in LinkFileB how do I modify the code below to also include that additional record in xdoc3?

 Dim findNode As XElement = (From t In xdoc2.Root.Elements() _
                                Where t.Name.ToString().Equals(nodeName1) AndAlso t.Element("Link_ID").Value = node1.Element("Link_ID").Value _
                                Select t).FirstOrDefault()


Thank You.

V.
0
 
Fernando SotoCommented:
Hi Victor;

I added some code at the bottom just after this comment, '========= Added new code here.

' First XML fie
Dim xdoc1 As XDocument = XDocument.Load("C:\Working Directory\LinkFinalA.xml")
' Second XML file
Dim xdoc2 As XDocument = XDocument.Load("C:\Working Directory\LinkFinalB.xml")
' The new XML file
Dim xdoc3 As New XDocument(New XElement("Root"))
' Get a list of all the main nodes, Table1, Table2, ....
Dim rowsF1 = From t In xdoc1.Root.Elements() _
             Select t

' Loop through all the nodes in file 1 and process
For Each node1 As XElement In rowsF1
    ' Get the Table name of the node
    Dim nodeName1 As String = node1.Name.ToString()
    ' Find that same element in File 2
    Dim findNode As XElement = (From t In xdoc2.Root.Elements() _
                                Where t.Name.ToString().Equals(nodeName1) AndAlso t.Element("Link_ID").Value = node1.Element("Link_ID").Value _
                                Select t).FirstOrDefault()
    ' If the node was found lets process it                            
    If findNode IsNot Nothing Then
        ' A test to find out which node gets added to the new File 3
        Dim addToNew As Boolean = True
        ' Match the nodes from file 1 with file 2
        For Each child In node1.Elements()
            Dim foundChild As XElement = findNode.Elements().Where(Function(t) t.Name = child.Name).FirstOrDefault()
            If foundChild IsNot Nothing Then
                If child.Value = foundChild.Value Then
                    ' Node name and value were the same process next node
                    addToNew = False
                    Continue For
                Else
                    ' Not the same add node from file 2 to file 3
                    addToNew = True
                    Exit For
                End If
            End If
        Next
        If addToNew Then
            xdoc3.Root.Add(findNode)
        End If
    End If
Next

'========= Added new code here

' Get a list of all the Nodes that are in LinkFinalB but not in LinkFinalA
Dim notInFirst As List(Of XElement) = (From n In xdoc2.Root.Elements()
                                       Where Not xdoc1.Root.Elements().Any(Function(i) i.Name.ToString() = n.Name.ToString() AndAlso i.Element("Link_ID").Value = n.Element("Link_ID").Value) _
                                       Select n).ToList()

' Add all the nodes in the list to the new XML file
If notInFirst.Count() > 0 Then
    For Each node As XElement In notInFirst
        xdoc3.Root.Add(node)
    Next
End If

Open in new window

0
 
vcharlesAuthor Commented:
It worked.

Thank You very much.

Victor
0
 
Fernando SotoCommented:
Not a problem Victor, glad to help.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 16
  • 11
Tackle projects and never again get stuck behind a technical roadblock.
Join Now