################################################################################
# Copyright (C) Mellanox Technologies, Ltd. 2001-2013. ALL RIGHTS RESERVED.
# This software product is a proprietary product of Mellanox Technologies, Ltd.
# (the \"Company\") and all right, title, and interest in and to the software 
# product, including all associated intellectual property rights, are and shall 
# remain exclusively with the Company.  All rights in or to the software product 
# are licensed, not sold.  All rights not licensed are reserved. 
# This software product is governed by the End User License Agreement provided 
# with the software product.
################################################################################

# Upgrading from the Inbox Driver
# -------------------------------------------------------------------------------
# To upgrade the driver perform the following:
#   1. Run the tool using the command line with the following parameters:
#      > Tenable-Upgrade.exe -arguments -Operation b -ConnectXProOnly 0
#   2. Upgrade the driver.
#   3. Run the tool using the command line with the following parameters:
#      > Tenable-Upgrade.exe -arguments -Operation r -EraseFiles [Optional] <0 | 1>

# Note: EraseFiles - [Optional, default value is 0] Enables backup files removal 
#                   upon completion of the configuration restoration.
#                   0 value - Do not remove the files.
#                   1 value - Remove the files.
#
# The tool backs up the configuration and then restores it.

# Upgrading from the Mellanox Driver
# -------------------------------------------------------------------------------
# To upgrade the driver perform the following:
#   1. Run the tool using the command line with the following parameters:
#      > Tenable-Upgrade.exe -arguments -Operation b -ConnectXProOnly 1
#   2. Upgrade the driver.
#   3. Run the tool using the command line with the following parameters:
#      > Tenable-Upgrade.exe -arguments -Operation r -EraseFiles [Optional] <0 | 1>

# Note: EraseFiles - [Optional, default value is 0] Enables backup files removal 
#                   upon completion of the configuration restoration.
#                   0 value - Do not remove the files.
#                   1 value - Remove the files.
# -------------------------------------------------------------------------------
# There are also two hidden parameters, that let us to control the support of 
# Temaing and Hyper-V.
# The parameters are:
#   1. -SupportHVT - Enables the support of restoring the configuration of Hyper-V/Teaming.
#                     Legal values:
#                         0 value - [Default] Do not support Hyper-V and Teaming.
#                        1 value - support restoring Hyper-V and Teaming configuration.
#   2. -dryBackup - Enables the tool to remove the Teams and changes the V-Switches to private
#                   when the backup is done.
#                   Legal values:
#                         0 value - Remove the teams and change the V-Switches to private.
#                        1 value - [Default] Do not change the configuration of the Teams/Hyper-V.
#
# -ExecutionMode  - [Optional, default value is 1] whether we are running as part of the setup or not. default is  run in setup execution mode.
#                   
#                   1 value - setup mode.
#                   2 value - standalone mode.
# -$EthInfPath -   [Optional] The path to the folder of Ethernet INF file, user should set this argument when execution mode is standalone, by default the value will be the installation folder."
# -$IbInfpath -    [Optional] The path to the folder of IPoIB INF file, user should set this argument when execution mode is standalone, by default the value will be the installation folder."
# -$BackupRoceMode - [Optional, default is 0] Whether to backup the roce mode or not
#                   0 value - Do not backup and restore the roce mode
#                   1 value - Backup and restore the roce mode

# -------------------------------------------------------------------------------



#Param([string] $Operation, [string] $EraseFiles, [string] $Path, [string] $ConnectXProOnly, [string] $SupportHVT, [string] $dryBackup, [string] $ExecutionMode , [string] $EthInfPath, [string] $IbInfpath ,[string]$BackupRoceMode)

#if ($Operation)
#{    
#    Write-Host "Operation = $Operation";
#}
#if ($EraseFiles)
#{    
#    Write-Host "Erase Files = $EraseFiles";
#}
#if ($Path)
#{    
#    Write-Host "Path = $Path";
#}
#if ($ConnectXProOnly)
#{    
#    Write-Host "ConnectX Pro Only = $ConnectXProOnly";
#}
#if ($SupportHVT)
#{    
#    Write-Host "Support Hyper-V and Teaming = $SupportHVT";
#}
#if ($dryBackup)
#{    
#    Write-Host "Dry backup = $dryBackup";
#}
#if ($executionMode)
#{    
#    Write-Host "Execution Mode = $executionMode";
#}

########################################################
# Errors
$ERROR_SUCCESS                      = 0;
$ERROR_EXCEPTION                    = -1;
$ERROR_NO_CARDS                     = -2;
$ERROR_UNKNOWN_INTERFACE_TYPE       = -3;
$ERROR_FILE_MISSING                 = -4;
$ERROR_CARD_MISSING                 = -5;
$ERROR_SET_REG_KEY                  = -6;
$ERROR_SET_NAME                     = -7;
$ERROR_SET_IP_CONFIGURATION         = -8;
$ERROR_SET_DNS_SERVER               = -9;
$ERROR_BAD_INPUT                    = -10;
$ERROR_INTERFACE_MISSING            = -11;
$ERROR_OS_VERSION_IS_NOT_SUPPORTED  = -12;
$ERROR_ADD_V_ADAPTER                = -13;
$ERROR_BAD_DLL_IMPORT               = -14;
$ERROR_MISSING_TOOLS               = -15;

$DefaultInstallDir = "C:\Program Files\Mellanox\MLNX_VPI"

# In this version we will not support hyper-V and teams/Vlans.
# Value zero means that we don't support them.
$UPGRADE_TEAMS_HYBPERV = 0;

# The default path of the backup file, log file and default values.
$DEFAULT_PATH = "C:\Users\Administrator\AppData\Local";

$selectedPath = $DEFAULT_PATH;
#exeution modes 
$SETUP = 1; # run as part of the setup(this the default)
$STANDALONE = 2; # run a standalone script 
##########################################################
# The function returns the indexx of a given string in a given array.
# 
# @param $arr - The array to be searched in.
# @param $str - The string to be found.
#
# @return:
#     - The index of the string in the array, in case it's found in the array.
#    - otherwise -1.
function getIndex($arr, $str)
{
    for ($i = 0; $i -lt $arr.length; $i++)
    {
        if ($arr[$i] -eq $str)
        {
            return $i;
        }
    }
    return -1;
}
function getBusDriverVersion()
{
    $busDriverPath = Join-Path $env:windir (((Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\mlx4_bus -Name ImagePath).imagepath)  -replace "systemroot\\", "");
    $busDriverVersion = (Get-Item $busDriverPath).VersionInfo.FileVersion;
    Write-Host $busDriverVersion
    return $busDriverVersion;
}


##########################################################
# The function prints the network adapters
# 
# ########################################################
function printNetAdapters()
{
    "Adapters list: " >> $logFile
    $adapters = @(Get-NetAdapter)
    $i = 0
    for($i;$i -lt $adapters.Count; $i++)
    {
        $adapters[$i].Name + "     " + $adapters[$i].InterfaceDescription  >> $logFile
    }

}

# Parsing the inputs.
$index = getIndex $args "-Path";
if ($index -gt -1)
{    
    $Path = $args[$index+1];
    Write-Host "Path = $Path";
}
if ($Path)
{
    if(!(Test-Path $Path))
    {
        write-host "ERROR - Invalid path.";
        exit $ERROR_BAD_INPUT;
    }
    $filePath = "$Path\BackupFile.xml";
    $defaultsPath = "$Path\Defaults.xml";
    $logFile = "$Path\upgradeLogFile.txt";
    $selectedPath = $Path;
} else
{
    $filePath = "$DEFAULT_PATH\BackupFile.xml";
    $defaultsPath = "$DEFAULT_PATH\Defaults.xml";
    $logFile = "$DEFAULT_PATH\upgradeLogFile.txt";
}

$index = getIndex $args "-Operation";
if ($index -gt -1)
{    
    $Operation = $args[$index+1];
    Write-Host "Opertaion = $Operation" ;
}

$index = getIndex $args "-EraseFiles";
if ($index -gt -1)
{    
    $EraseFiles = $args[$index+1];
    if (($EraseFiles -ne 0) -and ($EraseFiles -ne 1))
    {
        Write-Host "ERROR - Bad value for EraseFiles, see usage."
        "ERROR - Bad value for EraseFiles, see usage." >> $logFile;
        exit $ERROR_BAD_INPUT;
    }
    Write-Host "Erase Files = $EraseFiles";
} else
{
    $EraseFiles = 0;
}

$index = getIndex $args "-ConnectXProOnly";
if ($index -gt -1)
{    
    $ConnectXProOnly = $args[$index+1];
    Write-Host "ConnectX Pro Only = $ConnectXProOnly";
}

$index = getIndex $args "-SupportHVT";
if ($index -gt -1)
{    
    $SupportHVT = $args[$index+1];
    if (($SupportHVT -ne 0) -and ($SupportHVT -ne 1))
    {
        Write-Host "ERROR - Bad value for SupportHVT, see usage."
        "ERROR - Bad value for SupportHVT, see usage." >> $logFile;
        exit $ERROR_BAD_INPUT;
    }
    Write-Host "Support Hyper-V and Teaming = $SupportHVT";
} else
{
    $SupportHVT = 0;
}

$index = getIndex $args "-dryBackup";
if ($index -gt -1)
{    
    $dryBackup = $args[$index+1];
    if (($dryBackup -ne 0) -and ($dryBackup -ne 1))
    {
        Write-Host "ERROR - Bad value for dryBackup, see usage."
        "ERROR - Bad value for dryBackup, see usage." >> $logFile;
        exit $ERROR_BAD_INPUT;
    }
    Write-Host "Dry backup = $dryBackup";
} else
{
    $dryBackup = 1;
}

$index = getIndex $args "-RestartAppPath";
if ($index -gt -1)
{    
    $restartAppPath = $args[$index+1];
} else
{
    # Get the path dynamically
    $restartAppPath = [System.AppDomain]::CurrentDomain.BaseDirectory
}

$index = getIndex $args "-InstallDir";
if ($index -gt -1)
{    
    $installDir = $args[$index+1];
    Write-Host "Set install dir to $installDir "  
} else
{
    # Get the path dynamically
    $installDir = $DefaultInstallDir;
}

$index = getIndex $args "-ExecutionMode";
if ($index -gt -1)
{
     $executionMode = $args[$index+1];
     Write-Host "Execution mode = $executionMode"

}else
{
    $executionMode = $SETUP;
}
 
$index = getIndex $args "-EthInfPath";
if ($index -gt -1)
{
    $EthInfPath = $args[$index+1];
}

$index = getIndex $args "-IbInfPath";
if ($index -gt -1)
{
    $IbInfPath = $args[$index+1];
}
$index = getIndex $args "-BackupRoceMode";
if ($index -gt -1)
{
     $BackupRoceModep = $args[$index+1];
    if (($BackupRoceModep -ne 0) -and ($BackupRoceModep -ne 1))
    {
        Write-Host "ERROR - Bad value for $BackupRoceModep, see usage."
        "ERROR - Bad value for $BackupRoceModep, see usage." >> $logFile;
        exit $ERROR_BAD_INPUT;
    }
    Write-Host "Backup RoCE mode = $BackupRoceModep";
} else
{
    $BackupRoceModep = 0;
}

if($executionMode -eq  $STANDALONE)
{
    # in standalone mode the package does not installed and therefoe we need that all inf files and additional tools will be in $restartAppPath
    $installDir = $restartAppPath
}

if (($Operation -eq "r") -or ($Operation -eq "restore") -or ($executionMode -eq  $STANDALONE))
{
    if(!(Test-Path $restartAppPath))
    {
        $errMessage = "ERROR - Invalid restart application path = $restartAppPath.";
        $errMessage >> $logFile;
        Write-Host $errMessage;
        exit $ERROR_BAD_INPUT;
    }
    Write-Host "Restart application path = $restartAppPath";
}


#########################################################################
########################### Global Variables ############################
#########################################################################

#if (!$EraseFiles)
#{    
#    $EraseFiles = 0;
#}

# Pathes of the interfaces in the registry.
$IBA = "IBA"
$MLX4 = "MLX4"
$HKLMPath = "HKLM:\SYSTEM\CurrentControlSet"
$servicePath = "$HKLMPath\Services"
$interfacesClass = "$HKLMPath\Control\Class"
$networkPath = "$HKLMPath\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}"
$tcpIPParametersPath = "$servicePath\Tcpip\Parameters"
$tcpIPPath = "$tcpIPParametersPath\Interfaces"
$tcpIP6Path = "$servicePath\TCPIP6\Parameters\Interfaces"
$pciPath = "$HKLMPath\Enum";
$ipoibInterafcesPath = "$pciPath\$IBA";
$ethInterafcesPath = "$pciPath\$MLX4";
$netBTPath = "$servicePath\NetBT\Parameters\Interfaces";
$teamsPath = "$pciPath\COMPOSITEBUS\MS_IMPLAT_MP";
$mlx4BusParametersPath = "$servicePath\mlx4_bus\Parameters";
$roceModePath = "$mlx4BusParametersPath\Roce";

# The path of the nodes of the interfaces names in the backup file. 
$rootElement = "/RootElement";
$backupConfigurationPath = "$rootElement/BackupConfiguration";
$interfacesPathInBackup = "$backupConfigurationPath/Inter";
$cardsPathInBackup = "$rootElement/Card";
$nicsPathInBackup = "$backupConfigurationPath/NIC";
$DNSSuffixesPathInBackup = "$backupConfigurationPath/DNSSuffixes";
$performancePathInBackup = "$backupConfigurationPath/PerformanceTuning";
$teamsPathInBackup = "$backupConfigurationPath/Teams";
$NDProvidersPathInBackup = "$backupConfigurationPath/NDProviders";
$HyperVPathInBackup = "$backupConfigurationPath/Hyper-V";
$RocePathInBackup = "$backupConfigurationPath/Roce";

$DEFAULT_HEADER_IB = "DefaultValuesIB";
$DEFAULT_HEADER_ETH = "DefaultValuesETH";

$STAT_VERSION = "4.40"
$WIN2K12INBX_VERSION = "4.4"

# The pathes of the inf files.
$ETH = "ETH"
$IPOIB = "IPoIB"
$IPOIBP = "IPoIBP"
if($EthInfPath -eq $Null)
{
    $ethINFFileDirectory = Join-Path(Join-Path $installDir $ETH) "mlx4eth63.inf";
}else
{
    $ethINFFileDirectory = Join-Path  $EthInfPath "mlx4eth63.inf";
}
if($IbInfPath -eq $Null)
{
    $ibINFFileDirectory = Join-Path(Join-Path(Join-Path $installDir "IB") $IPoIB) "ipoib6x.inf";
}else
{
    $ibINFFileDirectory = Join-Path $IbInfPath "ipoib6x.inf";
}

Write-Host "ETH inf = $ethINFFileDirectory "
Write-Host "IpoIB inf = $ibINFFileDirectory "
# Tuning scenarios.
$TUNING_SCENARIO    = "TuningScenario"
$SINGLE_PORT_STREAM = 1086
$DUAL_PORT_STREAM   = 1087
$FORWARDING_STREAM  = 1088
$MCAST_STREAM       = 1096
$SINGLE_STREAM      = 1098

# IP configuration variables.
$IP_CONFIGURATION_VARIABLES = @("NameServer", "SubnetMask", "DefaultGateway", "IPAddress", "DefaultGatewayMetric", "InterfaceMetric", "Domain", "RegistrationEnabled", "RegisterAdapterName");

# Team Configuration variables.
$TEAM_CONFIGURATION_VARIABLES = @("Name", "TeamingMode", "LoadBalancingAlgorithm");

# Device Configuration variables.
$DEVICE_CONFIGURATION_VARIABLES = @("PortType");
$OPTIONAL_DEVICE_CONFIGURATION_VARIABLES = @("EnableRoce", "EnableRRoce");

# Mellanox interfaces types.
$INTERFACES_TYPES = @($IBA, $MLX4);

# ND-Providers.
$MLX4ND  = "mlx4nd";
$MLX4ND2 = "mlx4nd2";
$IBAL    = "ibal";

# Const variables.
$CONNECTX_PRO_ID     = "1007"
$MLNX_VEN_ID         = "VEN_15B3";
$SUBNET_MASK_LENGTH  = 4;
$BITS_COUNT          = 8;

# Roce values
$ROCE_MODE            = 0;
$RROCE_OVER_IP_MODE   = 1;
$RROCE_OVER_UDP_MODE  = 2;
$NO_ROCE_MODE         = 4;

$Supported_OS = @("2012", "2012 R2");
$mlxSetupWin2012R2Del = $Null;
$mlxSetupWin2012R2Find = $Null;
$mlxSetupWin2012 = $Null;
#############################################################
function WriteToLog($msg,$logFile)
{
    $msg >> $logFile;
    Write-Host $msg;
}

function ImportMlxSetupMethods($mlxSetupPath)
{
    try
    {
        $env:Path += ";" + $mlxSetupPath;
        $DeleteCx3ProMethodDefinition = @'
        [DllImport("mlx_setup.dll", CharSet = CharSet.Unicode)]
        public static extern bool DeleteCX3PROAdaptersBfrRestore(ulong hInstaller, bool  bSetMSIProps);
'@
    
        $mlxSetupWin2012R2Del = Add-Type -MemberDefinition $DeleteCx3ProMethodDefinition -Name 'mlxsetup' -Namespace 'MLNXDelCx3Pro' -PassThru;

        $FindCX3ProMethodDefinition = @'
        [DllImport("mlx_setup.dll", CharSet = CharSet.Unicode)]
        public static extern bool FindOldCX3ProAdapters(ulong hInstaller, bool  bSetMSIProps);
'@
    
        $mlxSetupWin2012R2Find = Add-Type -MemberDefinition $FindCX3ProMethodDefinition -Name 'mlxsetup' -Namespace 'MLNXFindCx3Pro' -PassThru;

        $RemoveCX3MethodDefinition = @'
        [DllImport("mlx_setup.dll", CharSet = CharSet.Unicode)]
        public static extern bool RemoveWin2k12InbxAdapters(ulong hInstaller);
'@
    
        $mlxSetupWin2012 = Add-Type -MemberDefinition $RemoveCX3MethodDefinition -Name 'mlxsetup' -Namespace 'MLNXDelCx3' -PassThru;
    }
    catch
    {
        $errMessage = "ERROR - failed to load function from mlx_setup.dll at $mlxSetupPath.  Exception data $_";
        $errMessage >> $logFile;
        Write-Host $errMessage;
        exit $ERROR_BAD_DLL_IMPORT;
    }
    return $mlxSetupWin2012R2Del,$mlxSetupWin2012R2Find,$mlxSetupWin2012

}

function IsWinPE
{
   return Test-Path -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinPE"
   
}
function ValidateStandAloneTools($toolsPath,$logFile)
{
    $res = $True;
    if ((Test-Path (Join-Path $restartAppPath "mlx_setup.dll")) -eq $False)
    {
        $res = $False;
        WriteToLog "mlx_setup.dll is missing at $restartAppPath" $logFile;
    }
    if ((Test-Path (Join-Path $restartAppPath "Tenable-Upgrade.ps1")) -eq $False)
    {
        $res = $False;
        WriteToLog "Tenable-Upgrade.ps1 is missing at $restartAppPath" $logFile;
    }
    return $res
}

# Check if the current OS version is supported.
$currentOSVer = (Get-WmiObject Win32_OperatingSystem).Version;
$isWinPE = IsWinPE ;

if (($currentOSVer -lt 6.2) -or ($currentOSVer -ge 6.4) -or ( $isWinPE -eq $True))
{
    
    $errorMessage =  "Error - Operating system version is not supported, version = $currentOSVer(WinPE = $isWinPE)";
    Write-Host $errorMessage;
    $errorMessage >> $logFile;
    if ($executionMode -eq $STANDALONE)
    {
        return $ERROR_SUCCESS;
    }else
    {
        return $ERROR_OS_VERSION_IS_NOT_SUPPORTED;
    }
}

if($executionMode -eq $STANDALONE)
{
    WriteToLog "Working in execution mode $executionMode"
    if( (ValidateStandAloneTools $restartAppPath $logFile) -eq $False)
    {
         exit $ERROR_MISSING_TOOLS;
    }
    ($mlxSetupWin2012R2Del,$mlxSetupWin2012R2Find,$mlxSetupWin2012) = ImportMlxSetupMethods $restartAppPath ;
    $busDriverVersion = getBusDriverVersion;
    WriteToLog "Bus driver version $busDriverVersion" $logFile
    WriteToLog "os version $currentOSVer" $logFile;
    if (($currentOSVer -lt 6.3) -and ($currentOSVer -gt 6.1) )
    {
        if($busDriverVersion -eq "4.1.10092")
        {
            
            if (($Operation -eq "b") -or ($Operation -eq "backup"))
            {
                if((Test-Path HKLM:\Software\Mellanox) -eq $False)
                {
                    New-item -path HKLM:\Software\Mellanox
                }
               Set-ItemProperty -path HKLM:\Software\Mellanox -name InboxWin2k12Upgrade -Value 1;
            }else
            {
                $msg = "Restore is not supported for inbox driver";
                Write-Host $errorMessage;
                $errorMessage >> $logFile;
                exit 0;
            }
        }else
        {
            $exist = Get-ItemProperty -path HKLM:\Software\Mellanox -name InboxWin2k12Upgrade -ErrorAction SilentlyContinue;
            if ( (($Operation -eq "r") -or ($Operation -eq "restore")) -and ($exist -ne $Null)) 
            {
                WriteToLog "Start to remove old adapters" $logFile
                $mlxSetupWin2012::RemoveWin2k12InbxAdapters(0);
            }elseIf(($Operation -eq "b") -or ($Operation -eq "backup"))
            {
                WriteToLog "saving configuration in stand alone mode is required only for inbox drivers"
                exit 0;
            }else
            {
                #InboxWin2k12Upgrade does not exist no need to run restore.
                WriteToLog "restore already done once no need to do anything"
                exit 0;
            }
        }
    }elseIf (($currentOSVer -lt 6.4) -and ($currentOSVer -gt 6.3) )
    {
        if($busDriverVersion -eq "4.4.13905")
        {
            if (($Operation -eq "b") -or ($Operation -eq "backup"))
            {
                WriteToLog "namespace is $mlxSetupWin2012R2Find" $logFile;
                WriteToLog $env:Path $logFile;
                $foundCX3PROAdpters = $mlxSetupWin2012R2Find::FindOldCX3ProAdapters(0,$False);
               if( $foundCX3PROAdpters -eq $False)
               {
                    # no need to save configuration, we did not find any Connectx-3 PRO  adapters
                    $msg = "We did not find any Connectx3 PRO adapters, no need to save and restore configuration";
                    WriteToLog $msg $logFile;
                    exit 0;
               }else
               {
                    $ConnectXProOnly = 1;
               }
            }else
            {
                $msg = "Restore is not supported on inbox drivers";
                WriteToLog $msg $logFile;
                exit $ERROR_SUCCESS;
            }

         }else
         {
            $exist = Get-ItemProperty -path HKLM:\Software\Mellanox -name CX3PROADAPTERS -ErrorAction SilentlyContinue
            if ( (($Operation -eq "r") -or ($Operation -eq "restore")) -and ($exist -ne $Null)) 
            {
                $ConnectXProOnly = 1;
                $mlxSetupWin2012R2Del::DeleteCX3PROAdaptersBfrRestore(0,$False);
                remove-itemproperty -path HKLM:\Software\Mellanox -name CX3PROADAPTERS;
            }else
            {
                $msg = "No Action is required";
                WriteToLog $msg $logFile;
                exit $ERROR_SUCCESS;
            }
         }

    }else
    {
         WriteToLog "Unknown operating system ,os version $currentOSVer" $logFile;
    }
}
#########################################################################
##################### Functions Used to the Backup ######################
#########################################################################

# The function adds a node to xml file with text data.
#
# @param $xmlHandle - A xml handle that we want to add the node to.
# @param $nodeName - The name of the node we want to add.
# @param $data - The data we want to save in the node.
function addXmlNode($xmlHandle, $nodeName, $data)
{
    $xmlNode = $XmlWriter.CreateElement($nodeName);
    $xmlText = $XmlWriter.CreateTextNode($data);
    $xmlNode.AppendChild($xmlText);
    $xmlHandle.AppendChild($xmlNode);
}

# The function saves under "$xmlTcpIP" the registry key "$regKeyName" in case it exists 
# in the registry in the tcpIP configuration.
#
# @param $xmlTcpIP - the xml handle we want to save the data under it.
# @param $tcpIpProperties - The tcp IP configuration of the adapter.
# @param $regKeyName - The name of the registry key.
function saveRegKey($xmlTcpIP, $tcpIpProperties, $regKeyName)
{
    if ($tcpIpProperties.$regKeyName)
    {
        addXmlNode $xmlTcpIP $regKeyName $tcpIpProperties.$regKeyName;
    }
}

# The function saves the network configuration.
#
# @param $xmlAdapter - the xml handle we want to save the data under it .
# @param$$instanceIdAdapter - the PNP instance id of the adapter we want to save it's configuration.
function saveIPConfig($xmlAdapter, $instanceIdAdapter)
{
    $tcpIpProperties =  @(Get-ItemProperty -Path $tcpIPPath\$instanceIdAdapter);
    $tcpIp6Properties =  @(Get-ItemProperty -Path $tcpIP6Path\$instanceIdAdapter);

    # Backup the tcp IP configuration.
    if (($tcpIpProperties.length -gt 0) -or (Test-Path -Path $netBTPath\$instanceIdBT))
    {
        $xmlTcpIP = $XmlWriter.CreateElement("TcpIP");
        if ($tcpIpProperties.length -gt 0)
        {
            for ($i = 0; $i -lt $IP_CONFIGURATION_VARIABLES.length; $i++)
            {
                saveRegKey $xmlTcpIP $tcpIpProperties $IP_CONFIGURATION_VARIABLES[$i];
            }
        }
        if (Test-Path -Path $netBTPath\$instanceIdBT)
        {
            try 
            {
                $instanceIdBT = "Tcpip_" + $instanceIdAdapter;
                $netBiosProperty = (Get-ItemProperty -Path $netBTPath\$instanceIdBT -ErrorAction Stop);
                $netBiosOptions = $netBiosProperty.NetbiosOptions;
                $nameServerList = $netBiosProperty.NameServerList;
                addXmlNode $xmlTcpIP "NetBiosOptions" $netBiosOptions
                if ($nameServerList)
                {
                    addXmlNode $xmlTcpIP "NameServerList" $nameServerList
                }
            } catch
            {
                "Error - Failed to save the netBiosOptions with error = " + $_ >> $logFile
            }
        }
        $xmlAdapter.AppendChild($xmlTcpIP);
    }
        
    # Backup the tcp IP6 configuration.
    if ($tcpIp6Properties.length)
    {
        $xmlTcpIP6 = $XmlWriter.CreateElement("TcpIP6");
        
        $xmlAdapter.AppendChild($xmlTcpIP6);
    }
}

# The function saves the configuration of the network.
# Also it adds a node that contains the interface name, it's guid, it's friendly name.
#
# @param $xmlAdapter - the xml handle we want to save the data under it.
# @param $instanceIdAdapter - The instance id of the adapter, defined in the registry by the OS.
# @param $interfaceID -  The guid of the interface.
# @param $FriendlyName - The friendly name of the interface.
# @param $locationInfo - The location information of the adapter.
function getNetworkConfiguration($xmlAdapter, $instanceIdAdapter, $interfaceID, $FriendlyName, $locationInfo)
{
    try
    {
        $pnPInstanceId = @(Get-ItemProperty -Path $networkPath\$instanceIdAdapter\Connection -ErrorAction Stop).PnPInstanceId
        $name_t = @(Get-ItemProperty -Path $networkPath\$instanceIdAdapter\Connection -ErrorAction Stop).Name;
        $newInterface = $XmlWriter.CreateElement("Inter");
        $guid = $interfaceID -split "-";
        if ($guid[1])
        {
            $guid = $guid[0] + "-" + $guid[1];
        } else
        {
            $guid = $guid[0];
        }
        # In the backup file we save the guid for the interfaces only for non virtual adapters,
        # that will help us to distinguish between the interfaces.
        switch ($pnPInstanceId)
        {
            {$_ -match $ETH} {
                $newInterface.SetAttribute("Guid", $guid);
                $newInterface.SetAttribute("Type", "eth");
            }
            {$_ -match $IPOIB} {
                $newInterface.SetAttribute("Guid", $guid);
                $newInterface.SetAttribute("Type", "ib");
            }
            {$_ -match $IPOIBP} {
                $newInterface.SetAttribute("IPoIBP", "yes");
                $newInterface.SetAttribute("Type", "ib");
            }
            default {
                "Error - Unknown type of the interface, type = $pnPInstanceId." >> $logFile;
            }
        }
        $newInterface.SetAttribute("Name", $name_t);
        $newInterface.SetAttribute("DriverDesc", $FriendlyName);
        $newInterface.SetAttribute("InstanceID", $instanceIdAdapter);
        $newInterface.SetAttribute("LocationInfo", $locationInfo);
        $BackupConfiguration.AppendChild($newInterface);
            
        addXmlNode $xmlAdapter "Name" $name_t;
        
        saveIPConfig $xmlAdapter $instanceIdAdapter;
        
        $XmlWriter.Save($filePath);
    } catch
    {
        $ErrorMessage = "ERROR - Get Network Configuration of interface failed with error: " + $_.Exception.Message;
        $ErrorMessage >> $logFile;
        return $ERROR_EXCEPTION;
    }
    return $ERROR_SUCCESS;
}
    
# The function backup all the registry keys of the interface, also it saves all the network configuration.
# Also it adds a node that contains the interface name, it's guid, it's friendly name.
# Aslo it adds a node that contains the current scenario tuning.
#
# @param $xmlAdapter - the xml pointer we want to save the data under it.
# @param $adapter - the driver key of the adapter we want to save it's configuration.
# @param $type - the type of the interface, "IBA" or "MLX4".
# @param $interfaceID -  The guid of the interface.
# @param $FriendlyName - The friendly name of the interface.
# @param $locationInfo - The location of the NIC.
function getInterfaceConfiguration($xmlAdapter, $adapter, $type, $interfaceID, $FriendlyName, $locationInfo)
{
    $err = $Error_SUCCESS;
    try
    {
        $adapterProperties = @(Get-ItemProperty -Path $interfacesClass\$adapter -ErrorAction Stop);
        $netCfgInstanceId = $adapterProperties.NetCfgInstanceId;
        $adapterProperties = $adapterProperties -replace "@", "";
        $adapterProperties = $adapterProperties -replace "{", "";
        $adapterProperties = $adapterProperties -replace "}", "";
        $adapterProperties = $adapterProperties -split ";";
        $headNode = $XmlWriter.CreateElement("BasicConfiguration");
        $xmlAdapter.AppendChild($headNode);
        for ($i = 0; $i -lt $adapterProperties.length; $i++)
        {
            $valueInReg = $adapterProperties[$i] -split "=";
            $valueInReg[0] = $valueInReg[0] -replace " " , "";
            $regKeyName = $valueInReg[0];
            $regKeyValueSave = 1;
            if (Test-Path -Path "$interfacesClass\$adapter\ndi\params\$regKeyName")
            {
                $regKeyParams = @(Get-ItemProperty -Path "$interfacesClass\$adapter\ndi\params\$regKeyName" -ErrorAction Stop);
                if ($valueInReg[1] -eq $regKeyParams.default)
                {
                    $regKeyValueSave = 0;
                }
            } 
            if ($regKeyValueSave -eq 1)
            {
                $currRegKey = $XmlWriter.CreateElement("RegKey");
                $currRegKey.SetAttribute("Name", $valueInReg[0]);
                $currRegKey.SetAttribute("Value", $valueInReg[1]);
                $headNode.AppendChild($currRegKey);
            }
            
            $name_t = @(Get-ItemProperty -Path $networkPath\$netCfgInstanceId\Connection -ErrorAction Stop).Name;
            # Saving the scenario tuning, in case it exists.
            if ($valueInReg[0] -eq $TUNING_SCENARIO)
            {
                $pnPInstanceId = @(Get-ItemProperty -Path $networkPath\$netCfgInstanceId\Connection -ErrorAction Stop).PnPInstanceId
                $scenario = $XmlWriter.CreateElement("ScenarioTuning");
                $scenario.SetAttribute("Scenario", $valueInReg[1]);
                $scenario.SetAttribute("AdapterName", $name_t);
                
                switch ($pnPInstanceId)
                {
                    {$_ -match $IPOIB} {
                        $scenario.SetAttribute("adapterType", "ib");
                    } 
                    {$_ -match $ETH} {
                        $scenario.SetAttribute("adapterType", "eth");
                    }
                    default {}
                }
                $scenario.SetAttribute("LocationInfo", $locationInfo);
                if ($BackupConfiguration.PerformanceTuning)
                {
                    $BackupConfiguration.PerformanceTuning.AppendChild($scenario);
                } else
                {
                    $perfTuning = $XmlWriter.CreateElement("PerformanceTuning");
                    $perfTuning.AppendChild($scenario);
                    $BackupConfiguration.AppendChild($perfTuning);
                }
            }
        }
        $result = getNetworkConfiguration $xmlAdapter $netCfgInstanceId $interfaceID $FriendlyName $locationInfo;
        if ($result.SyncRoot)
        {
            $err = $result.SyncRoot[$result.length - 1];
        } else
        {
            $err = $result;
        }
        $XmlWriter.Save($filePath);
    } catch
    {
        $ErrorMessage = "ERROR - Get Configuration of interface failed with error: " + $_.Exception.Message;
        $ErrorMessage >> $logFile;
        return $ERROR_EXCEPTION;
    }
    return $err;
}

# The function save the configuration of the adapters of the NIC "$card".
#
# @parameter $locationInfo - The PCI of the card.
# @parameter $card - The card we want to backup the configuration of it's adapters.
# @parameter $interface -  The type of the interfaces we want to backup, it should be:
#                            "IPoIB", or "ETH".
function getAdapters($locationInfo, $card, $interface, $ConnectXPro)
{
    $statusError = $ERROR_SUCCESS;
    "Start Backing up the configuration of the $interface interfaces for card " + $card.Name >> $logFile;
    try
    {
        switch ($interface)
        {
            $IPOIB {
                $type = $IBA;
                $typePathInReg = $ipoibInterafcesPath;
            }
            $ETH {
                $type = $MLX4;
                $typePathInReg = $ethInterafcesPath;
            }
            default {
                $ErrorMessage =  "ERROR - Unknown interface type, type = $type";
                $ErrorMessage >> $logFile;
                return $ERROR_UNKNOWN_INTERFACE_TYPE;
            }
        }
        # When want are upgrading only for Connect-X Pro cards we take only the appropriate entries.
        if ($ConnectXPro -eq 1)
        {
            $typeinterafces = Get-ChildItem -path $typePathInReg -ErrorAction Stop | Where {$_.Name -match "-"} | Get-ChildItem;
        } else
        {
            $typeinterafces = Get-ChildItem -path $typePathInReg -ErrorAction Stop | Get-ChildItem;
        }
        If ($typeinterafces)
        {        
            # Adding IBA or MLX4 node
            $xmlType = $XmlWriter.CreateElement($type);
            foreach ($inter_t in $typeinterafces)
            {
                $headerFlag = 0;
                # Create the node of the card, we will add it when we find the first adapter.
                $adapter = @($inter_t | Get-ItemProperty -ErrorAction Stop);
                if ($adapter.HardwareID -match $IPOIBP)
                {
                    $isIpoibP = 1;
                } else
                {
                    $isIpoibP = 0;
                }
                # In eth the location name starts with "MLX4", we replace with "PCI" 
                # in order to have an uniform template. 
                $cleanLocalInfo = $adapter.LocationInformation;
                if ($cleanLocalInfo -match $MLX4)
                {
                    $cleanLocalInfo = $cleanLocalInfo -split " ";
                    $cleanLocalInfo[0] = "PCI";
                    $cleanLocalInfo = $cleanLocalInfo -as [string]
                }
                if ($locationInfo -eq $cleanLocalInfo)
                {
                    $friendlyNameExist = $adapter.FriendlyName
                    if (!$friendlyNameExist)
                    {
                        "Information - Found uninstalled interface : " + $inter_t >> $logFile
                    } else
                    {
                        # Only when we add the first interface we add the node of the card, $headerFlag = 0 means that this is the first node.
                        if ($headerFlag -eq 0)
                        {
                            $card.AppendChild($xmlType);
                            if ($isIpoibP -eq 1)
                            {
                                $xmlInterface = $XmlWriter.CreateElement("IPOIBP");    
                                $xmlType.AppendChild($xmlInterface);
                            } 
                            $headerFlag = 1;
                        }
                        $xmlAdapter = $XmlWriter.CreateElement("Interface");
                        $xmlAdapter.SetAttribute("FriendlyName", $adapter.FriendlyName);
                        
                        "Found interface " + $adapter.FriendlyName >> $logFile;
                        
                        $interfaceID =  ($inter_t.Name -split "\\")[6];
                        # For virtual adapters we save also save the local interface.
                        if ($isIpoibP -eq 1)
                        {
                            $iboibpName = @($interfaceID -split "-")[2];
                            $xmlAdapter.SetAttribute("LocalName", $iboibpName);
                            $localConnection = @($interfaceID -split "-")[0]  + @($interfaceID -split "-")[1];
                            $xmlAdapter.SetAttribute("interfaceID", $localConnection);
                            $xmlInterface.AppendChild($xmlAdapter);    
                        }else
                        {
                            $interfaceID = @($interfaceID -split "-")[0] + @($interfaceID -split "-")[1];
                            $xmlAdapter.SetAttribute("interfaceID", $interfaceID);
                            $xmlType.AppendChild($xmlAdapter);
                        }
                        $result = getInterfaceConfiguration $xmlAdapter $adapter.Driver $type $interfaceID $adapter.FriendlyName $locationInfo;
                        if ($result.SyncRoot)
                        {
                            $err = $result.SyncRoot[$result.length - 1];
                        } else
                        {
                            $err = $result;
                        }
                        if ($statusError -eq $ERROR_SUCCESS)
                        {
                            $statusError = $err;
                        }
                    }
                }
            }
        } else 
        {
            $ErrorMessage =  "Info - No $interface interfaces found for card " + $card.Name;
            $ErrorMessage >> $logFile;
            $statusError = $ERROR_SUCCESS;
        }
    }
    catch
    {
        $ErrorMessage = "ERROR - Get Configuration of interface failed with error: " + $_.Exception.Message;
        $ErrorMessage >> $logFile;
        "Finished Backing up the configuration of the $interface interfaces with error." >> $logFile;
        $XmlWriter.Save($filePath);
        return $ERROR_EXCEPTION;
    }
    "Finished Backing up the configuration of the $interface interfaces." >> $logFile;
    $XmlWriter.Save($filePath);
    return $statusError;
}

# The function adds a node with a given name and given attribute as a child of the given handle.
#
# @param $xmlHandle - the handle we want to add new node to.
# @param $name - the name of the new node.
# @param $attribute - the attribute of the new node.
function addXmlNodeWithAttribute ($xmlHandle, $name, $attribute)
{
    $xmlNode = $XmlWriter.CreateElement($name);
    $xmlNode.SetAttribute("Name", $attribute);
    $xmlHandle.AppendChild($xmlNode);
}

# The function backup the the installed Nd providers in the machine.
function backupNDProviders()
{
    $ndInstallInstalled = @(get-command -type Application | Where {$_.Name -Match "ndinstall"});
    if ($ndInstallInstalled)
    {
        $ndv1 = ndinstall | Select-String "NDv1";
        $ndv2 = ndinstall | Select-String "NDv2";
        $ibal = ndinstall | Select-String "OpenFabrics Network Direct Provider";
        if ($ndv1 -or $ndv2 -or $ibal)
        {
            $ndProviders = $XmlWriter.CreateElement("NDProviders");
            $BackupConfiguration.AppendChild($ndProviders);
            if ($ndv1)
            {                
                addXmlNodeWithAttribute $ndProviders "Provider" $MLX4ND;
            }
            
            if ($ndv2)
            {
                addXmlNodeWithAttribute $ndProviders "Provider" $MLX4ND2;
            }
            
            if ($ibal)
            {
                addXmlNodeWithAttribute $ndProviders "Provider" $IBAL;
            }
        }
    }
}
    
# The function saves the ip configuration of a given team.
#
# @param $xmlTeam - A xml handle to save the data under it.
# @param $teamName - The name of the team we want to save it's configuration.
function getIPConfigurationTeam ($xmlTeam, $teamName)
{
    $err = $ERROR_SUCCESS;
    try
    {
        $currentTeamInReg = @((Get-ChildItem -Path $teamsPath -ErrorAction Stop | Get-ItemProperty).Driver);
        for ($i = 0; $i -lt $currentTeamInReg.length; $i++)
        {
            $pnPInstanceId = $currentTeamInReg[$i];
            $itemProperties = (Get-ItemProperty -Path $interfacesClass\$pnPInstanceId -ErrorAction Stop);
            $netCfgInstanceId = $itemProperties.NetCfgInstanceId;
            $name = (Get-ItemProperty -Path $networkPath\$netCfgInstanceId\Connection -ErrorAction Stop).Name;
            if ($teamName -eq $name)
            {
                $vlanId = $itemProperties.VlanId; 
                if ($vlanId)
                {
                    addXmlNode $xmlTeam "VlanId" $vlanId
                }
    
                saveIPConfig $xmlTeam $netCfgInstanceId;
            }
        }
    } catch
    {
        "Error - failed to save the IP configuration of team " + $team.Name + " with error = " + $_.Exception.Message >> $logFile;
        $err = $ERROR_EXCEPTION;
    }
    return $err;
}

# The function saves the installed teams in the machine.
# Also it removes the our iterfaces from the teams, if the team contains only our iterfaces 
# as members, then the team will be removed.
function backupTeams()
{
    $err = $ERROR_SUCCESS;
    "Start backup the teaming configuration." >> $logFile;
    [xml]$xmlBackFile = [xml](Get-Content $filePath);
    $interfaces_t = @($xmlBackFile.SelectNodes($interfacesPathInBackup)).Name;
    $interfacesNode = @($xmlBackFile.SelectNodes($interfacesPathInBackup));
    $teams = @(Get-NetLbfoTeam);
    $headerTeams = 0;
    $xmlTeamsHeader = $XmlWriter.CreateElement("Teams");
    if ($interfaces_t.length -gt 0)
    {
        foreach ($team in $teams)
        {
            "Saving the configuration of team " + $team.Name >> $logFile;
            $headerTeam = 0;
            $xmlTeam = $XmlWriter.CreateElement("Team");
            $members = @($team.Members);
            $membersNum = $members.length;
            foreach ($member in $members)
            {    
                if ($interfaces_t.Contains($member))
                {
                    # Add the header of the teams to the backup file only one time.
                    if($headerTeams -eq 0)
                    {
                        $BackupConfiguration.AppendChild($xmlTeamsHeader);
                        $headerTeams = 1;
                    }
                    # Add the header of the current team to the backup file only one time.
                    if($headerTeam -eq 0)
                    {
                        for ($i = 0; $i -lt $TEAM_CONFIGURATION_VARIABLES.length; $i++)
                        {
                            $var = $TEAM_CONFIGURATION_VARIABLES[$i];
                            addXmlNode $xmlTeam $var $team.$var;
                        }
                        
                        $teamNics = @($team.TeamNics);
                        foreach ($teamNic in $teamNics)
                        {
                            $xmlTeamNic = $XmlWriter.CreateElement("TeamNic"); 
                            addXmlNode $xmlTeamNic "Name" $teamNic
                            $result = getIPConfigurationTeam $xmlTeamNic $teamNic;
                            if ($result.SyncRoot)
                            {
                                $temp = $result.SyncRoot[$result.length - 1];
                            } else
                            {
                                $temp = $result;
                            }
                            if ($temp -ne $ERROR_SUCCESS)
                            {
                                $err = $temp;
                            }
                            $xmlTeam.AppendChild($xmlTeamNic);
                        }
                          
                        $xmlTeamsHeader.AppendChild($xmlTeam);
                        $headerTeam = 1;
                    }
                    $xmlMember = $XmlWriter.CreateElement("Member");
                    $memberType = ($interfacesNode | Where {$_.Name -eq $member}).Type;
                    $memberName = $XmlWriter.CreateTextNode($member);
                    $xmlMember.SetAttribute("Type", $memberType);
                    $xmlMember.AppendChild($memberName);
                    $xmlTeam.AppendChild($xmlMember);
                    
                    if ($dryBackup -ne 1)
                    {
                        $membersNum--;
                        if ($membersNum -eq 0)
                        {
                            try
                            {
                                Remove-NetLbfoTeam $team.Name -Confirm:$false -ErrorAction Stop;
                            } catch
                            {
                                "Error - failed to remove team " + $team.Name + " with error = " + $_.Exception.Message >> $logFile;
                                $err = $ERROR_EXCEPTION;
                            }
                        } else
                        {
                            try
                            {
                                Remove-NetLbfoTeamMember -Name $member -Team $team.Name -Confirm:$false -ErrorAction Stop;
                            } catch
                            {
                                "Error - failed to remove member " + $member + " from team " + $team.Name + " with error = " + $_.Exception.Message >> $logFile;
                                $err = $ERROR_EXCEPTION;
                            }
                        }
                    }
                }
            }
        }
    }
    "Finished backup the teaming configuration." >> $logFile;
    return $err;
}

# The function saves the configuration of the vSwitches connected to ouer interfaces, then it 
# converts them to internals.
function backupHyperVConfig()
{
    $err = $ERROR_SUCCESS;
    "Start backup the Hyper-V configuration." >> $logFile;
    $isHyperV = Get-Command -module Hyper-V;
    if ($isHyperV)
    {
        [xml]$xmlBackFile = [xml](Get-Content $filePath);
        $interfacesDriver = @($xmlBackFile.SelectNodes($interfacesPathInBackup));
        $headerSwitches = 0;
        $xmlSwitchesHeader = $XmlWriter.CreateElement("Hyper-V");
        $vSwitches = @(Get-VMSwitch | Where {$_.NetAdapterInterfaceDescription -match "Mellanox"});
        for ($i = 0; $i -lt $vSwitches.length; $i++)
        {
            $xmlSwitch = $XmlWriter.CreateElement("Switch");
            
            $interface = $interfacesDriver | Where {$_.DriverDesc -eq $vSwitches[$i].NetAdapterInterfaceDescription}
            if ($interface)
            {
                # Add the header of the switches to backup file only one time.
                if($headerSwitches -eq 0)
                {
                    $BackupConfiguration.AppendChild($xmlSwitchesHeader);
                    $headerSwitches = 1;
                }
                addXmlNode $xmlSwitch "Name" $vSwitches[$i].Name;
                addXmlNode $xmlSwitch "NetAdapter" $interface.Name;
                addXmlNode $xmlSwitch "NetAdapterType" $interface.Type;
                        
                $xmlSwitchesHeader.AppendChild($xmlSwitch);
                if ($dryBackup -ne 1)
                {
                    try
                    {
                        Set-VMSwitch -Name $vSwitches[$i].Name -SwitchType Private -ErrorAction Stop;
                    } catch
                    {
                        "Error - Failed to change the switch " + $vSwitches[$i].Name + " to private with error = " + $_.Exception.Message >> $logFile;
                        $err = $ERROR_EXCEPTION;
                    }
                }
            } else
            {
                "Error - Interafce with description " + $vSwitches[$i].NetAdapterInterfaceDescription + " is missing." >> $logFile;
                $err = $ERROR_INTERFACE_MISSING;
            }
        }
    }
    "Finished backup the Hyper-V configuration." >> $logFile;
    return $err;
}

# The function changes the names of the interfaces that backed up, it adds "_" to the names of
# the old interfaces so we can rename the new interfaces.
# When we pass input equal to 1, the function removes "_" from the names of the old interfaces, this will 
# help us to retrieve the old name in case we want to rollback.
#
# @param $rollBack - it indicates if we want to add "_" or remove it from the names.
#                     Value 1 - means remove it.
#                     Value 0 - means add it.
function renameInterfaces($rollBack)
{
    [xml]$xmlBackFile = [xml](Get-Content $filePath);
    $interfacesInstancesID = @($xmlBackFile.SelectNodes($interfacesPathInBackup));
    for ($i = 0; $i -lt $interfacesInstancesID.length; $i++)
    {
        $instanceID = $interfacesInstancesID[$i].InstanceID;
        if (Test-Path -Path "$networkPath\$instanceID\Connection")
        {
            $name_t = @(Get-ItemProperty -Path "$networkPath\$instanceID\Connection" -ErrorAction Stop).Name;
            if ($rollBack)
            {
                $newName = $name_t -replace "_", "";
            } else
            {
                $newName = "_" + $name_t;
            }
            Set-ItemProperty -Path $networkPath\$instanceID\Connection -Name "Name" -Value $newName -Type String -ErrorAction Stop;
        }
    }
}

# The function saves the configuration of DNS suffixes.
# This function isn't used since the DNS suffixes are global and no need to save them.
#
# @param $xmlHandle - xml handle to add the configuration node to.
function backupDNSSuffixesConfig ($xmlHandle)
{
    try {
        $tcpIPProperty = @(Get-ItemProperty -Path $tcpIPParametersPath -ErrorAction Stop;) 
        $searchList = $tcpIPProperty.SearchList
        $useDomainNameDevolution = $tcpIPProperty.UseDomainNameDevolution
        $dNSSuffixesXml = $XmlWriter.CreateElement("DNSSuffixes");
        if ($searchList)
        {
            addXmlNode $dNSSuffixesXml "SearchList" $searchList
        }
        addXmlNode $dNSSuffixesXml "UseDomainNameDevolution" $useDomainNameDevolution
        $xmlHandle.AppendChild($dNSSuffixesXml);
    } catch
    {
        "Information - Failed to save the configuration of DNS suffixes with error = " + $_.Exciption.Message >> $logFile;
    }
}
#########################################################################
##################### Functions Used to the Restore #####################
#########################################################################

function cmpDriverVersion ($driverVer1, $driverVer2)
{
    $ver1 = $driverVer1 -split "\.";
    $ver2 = $driverVer2 -split "\.";
    if ($ver1[0] -as [int] -lt $ver2[0] -as [int])
    {
        return -1;
    } else
    {
        if ($ver2[0] -as [int] -lt $ver1[0] -as [int])
        {
            return 1;
        } else
        {
            if ($ver1[1] -as [int] -lt $ver2[1] -as [int])
            {
                return -1;
            } else
            {
                if ($ver2[1] -as [int] -lt $ver1[1] -as [int])
                {
                    return 1;
                }
            }
        }
    }
    return 0;
}

function waitForCardLoad($card)
{
try
    {
        $restExePath = Join-Path $restartAppPath "RestartDriver.exe"
        $LocationInfoArray = parseLocationInfo $card.LocationInfo
        if (Test-Path $restExePath)
        {
            "Information - waitForCardLoad: PCI Bus location is  " + $LocationInfoArray[0] >> $logFile
           & $restExePath "w" $LocationInfoArray[0] $LocationInfoArray[1] $LocationInfoArray[2] >> $logFile
        } else
        {
            "Error - Restart application is missing." >> $logFile
            return $ERROR_FILE_MISSING;
        }
    } catch
    {
        "ERROR - Failed to wait for device card with location  " + $LocationInfoArray[0] + " with error = " + $_.Exciption.Message >> $logFile;
        return $ERROR_EXCEPTION;
    }
    # $LastExitCode contain the exit code of the last exeutable execution.
    if ($LastExitCode -ne $ERROR_SUCCESS)
    {
        "Error - Failed to wait for device with error = $LastExitCode" >> $logFile
    }
    return $LastExitCode
}
function restartCard($pnpDriverId,$LocationInfoArray)
{
    try
    {
        #$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path
        $restExePath = Join-Path $restartAppPath "RestartDriver.exe"
        if (Test-Path $restExePath)
        {
            if ($LocationInfoArray.Length -gt 0)
            {
                "Information - Restarting device " + $pnpDriverId + " and waiting for load completion " >> $logFile
                & $restExePath  "r" $pnpDriverId $LocationInfoArray[0] $LocationInfoArray[1] $LocationInfoArray[2] >> $logFile
            }else
            {
                "Information - Restarting device " + $pnpDriverId + " without waiting for load completion " >> $logFile
                & $restExePath  "r" $pnpDriverId >> $logFile
            }
        } else
        {
            "Error - Restart application is missing." >> $logFile
            return $ERROR_FILE_MISSING;
        }
    } catch
    {
        "ERROR - Failed to restart card with id " + $pnpDriverId + " with error = " + $_.Exciption.Message >> $logFile;
        return $ERROR_EXCEPTION;
    }
    # $LastExitCode contain the exit code of the last exeutable execution.
    if ($LastExitCode -ne $ERROR_SUCCESS)
    {
        "Error - Failed to restart device with id $pnpDriverId with error = $LastExitCode" >> $logFile
    }
    return $LastExitCode 
}

function getLocationInfo ($adapterName)
{
    [xml]$backupFile_t = Get-Content $filePath;
    $interfaces = $backupFile_t.SelectNodes($interfacesPathInBackup);
    $adapterLocationInfo = ($interfaces | Where {$_.Name -eq $adapterName}).LocationInfo;
    return $adapterLocationInfo
}

# The function get the default values of the registry keys defined as non-overwrite in the inf file.
# 
# @parameter ethINFFileDirectory - The path of the inf file.
# @parameter defaultValuesType - key of the node in the xml file, it should be "DefaultValuesETH" for the eth rgistry keys,
#                                and "DefaultValuesIB" for thr ib registry keys.
function getDefaultValuesInINF([string]$INFFileDirectory, [string]$defaultValuesType)
{
    $nonOverwrite = $(Get-Content -path $INFFileDirectory | Select-String "%REG_DWORD_NO_CLOBBER", "%FLG_ADDREG_NOCLOBBER");
    
    $defaultValues = $defaultsWriter.CreateElement($defaultValuesType);
    $root.AppendChild($defaultValues);
    for ($i = 0; $i -lt $nonOverwrite.length; $i++)
    {
        # Split the registry key name and remove spaces and replace "*" with "_".
        $regName =  (($nonOverwrite[$i] -split ",")[2] -replace " ","");
        $regName_t = $regName;
        $regName =  $($regName -replace "\*","");
        $regKey = @((Get-Content -path $INFFileDirectory | Select-String $regName | Select-String "default,") -split ",");
        if ($regKey[4]) {
            # Get the default of the registry key.
            $defaultRegKey = $($regKey[4] -replace " ","");
            $defaultRegKey = $($defaultRegKey -replace """","");
            # Add the key with the default value to the file
            $currRegKey = $defaultsWriter.CreateElement("RegKey");
            $currRegKey.SetAttribute("Name", $regName_t);
            $currRegKey.SetAttribute("Default", $defaultRegKey);
            $defaultValues.AppendChild($currRegKey);
        }
    }
    $defaultsWriter.Save($defaultsPath);
}

# The function converts subnet mask to prefix length.
#
# @param $subnetMask - the subnet mask we want to convert.
function convertSubnetMaskToPrefixLength($subnetMask)
{ 
    $PrefixArray = @() ;
    $PrefixLength = 0 ;
    $ByteArray = @($subnetMask -split "\."); 
             
    #This loop converts the bytes to bits, add zeroes when necessary 
    for($byteCount = 0; $byteCount -lt $SUBNET_MASK_LENGTH; $byteCount++)  
    { 
        $bitVariable = $ByteArray[$byteCount] 
        $bitVariable = [Convert]::ToString($bitVariable, 2) 
        if($bitVariable.Length -lt $BITS_COUNT) 
        { 
            $NumOnes = $bitVariable.Length 
            $NumZeroes = 8 - $bitVariable.Length 
            for($bitCount = 0; $bitCount -lt $NumZeroes; $bitCount++)  
            { 
                $Temp = $Temp  + "0" 
            }   
            $bitVariable = $Temp + $bitVariable 
        } 
              
        #This loop counts the bits in the prefix 
        for($bitCount = 0; $bitCount -lt $BITS_COUNT; $bitCount++)  
        { 
            if ($bitVariable[$bitCount] -eq "1") 
            {         
                $PrefixLength++  
            } 
            $PrefixArray = $PrefixArray + ($bitVariable[$bitCount]) 
        } 
    } 

    #Check if the subnet mask was contiguous, fail if it wasn't. 
    $Mark = $False 
 
    foreach ($bit in $PrefixArray)  
    { 
        if($bit -eq "0") 
        { 
            if($Mark -eq $False) 
            { 
                $Mark = $True 
            } 
        } 
        if($bit -eq "1") 
        { 
            if($Mark -eq $True) 
            { 
               "ERROR - Invalid subnet mask." >> $logFile; 
               return -1 
            }     
        }                  
    } 
 
    return $PrefixLength 
}

# The function restorse the network configuration (IP, SubnetMask, gateway, DNS server...) 
#
# @param $TcpIP - A handle to the xml node that contain the backup data of the tcp IPv4.
# @param $TcpIP6 - A handle to the xml node that contain the backup data of the tcp IPv6.
# @param $adapterName - The name of the adapter we want to restore it's configuration.
function restoreNetworkConfiguration ($TcpIP, $TcpIP6, $adapterName, $instanceID)
{
    $errorStatus = $ERROR_SUCCESS;
    $retryCount = 0;
    $index = (Get-NetAdapter | Where {$_.Name -eq $adapterName}).ifIndex
    while (!$index -and ($index -ne 0) -and ($retryCount -lt 30))
    {
        "Information - Waiting to interface $adapterName to go up" >> $logFile;
        Start-Sleep -s 1
        $index = (Get-NetAdapter | Where {$_.Name -eq $adapterName}).ifIndex
        $retryCount = $retryCount + 1;
    }
    $index = $index -as [string];
    if ($TcpIP)
    {
        $netCfgInstanceId = (Get-ItemProperty -Path $interfacesClass\$instanceID -ErrorAction Stop).NetCfgInstanceId;                
        # restore the ip configuration.
        $ip =  $TcpIP.IPAddress -as [string];
        $ips = @($ip -split " ") 
        if ($ip -and ($index -ge 0))
        {
            $subnetMask =  $TcpIP.SubnetMask -as [string];
            $subnetMasks = @($subnetMask -split " ")
            $defaultgateway = $TcpIP.DefaultGateway -as [string];
            $defaultgateways = @($defaultgateway -split " ") 
            $defaultGateWayMetric = $TcpIP.DefaultGatewayMetric -as [string];
            $defaultGateWayMetricsArray = @($defaultGateWayMetric -split " ")
            $defaultGateWayMetrics = @()
            $interfaceMetric = $TcpIP.InterfaceMetric
            for ($i = 0; $i -lt $defaultGateWayMetricsArray.length; $i++)
            {
                $metric = $defaultGateWayMetricsArray[$i] -as [int]
                if ($metric -gt 0)
                {
                    $defaultGateWayMetrics += $metric
                } else
                {
                    if ($interfaceMetric -gt 0)
                    {
                        $defaultGateWayMetrics += $interfaceMetric; 
                    } else
                    {
                        # This is the default value defined by msdn.
                        $defaultGateWayMetrics += 1;
                    }
                }
            }
            # Delete the old configuration in case it is still exist.
            try
            {
                Get-NetIPAddress –IPAddress $ips[0] -ErrorAction Stop | Remove-NetIPAddress -Confirm:$false -ErrorAction Stop;
            } catch
            {}
            try
            {
                Set-NetIPInterface –InterfaceIndex $index -DHCP Disabled -ErrorAction Stop;
                Remove-NetIPAddress -InterfaceIndex $index -Confirm:$false -ErrorAction Stop;
            } catch
            {}
            try
            {
                $netInterface = Get-WmiObject win32_networkAdapterConfiguration | where {$_.InterfaceIndex -eq $index}
                "Information - Restore the following ips for interface $adapterName : $ips" >> $logFile
                "Information - Restore the following ips for interface " + $netInterface.Description >> $logFile
                "Information - Restore the following ips for interface index " + $netInterface.InterfaceIndex >> $logFile
                "Information - Restore the following subnetmasks for interface $adapterName : $subnetMasks" >> $logFile
                for ($i = 0; $i -lt 3; $i++)
                {
                    $result = $netInterface.EnableStatic($ips, $subnetMasks)
                    if ($result.ReturnValue -eq 0)
                    {
                        "Information - Set IPs and subnet masks result = " + $result.ReturnValue >> $logFile
                        break;
                    } else
                    {
                        if ($i -lt 2)
                        {
                            "Information - Set IPs and subnet masks failed with result = " + $result.ReturnValue + " ,try again." >> $logFile
                            Start-Sleep -Seconds 1
                        } else
                        {
                            "Error - Set IPs and subnet masks failed with result = " + $result.ReturnValue >> $logFile
                            $errorStatus = $ERROR_SET_IP_CONFIGURATION;
                        }
                        $netInterface = Get-WmiObject win32_networkAdapterConfiguration | where {$_.InterfaceIndex -eq $index}
                    }
                }

                # Restore WINS configuration.
                $netBiosOptions = $TcpIP.NetBiosOptions
                $nameServerList = @($TcpIP.NameServerList -split " ")
                
                # No need to restore them since they are global and will not be removed.
                if ($false)
                {
                    $enableDNS = $TcpIP.EnableDNS
                    if (!$enableDNS)
                    {
                        $enableDNS = $FALSE
                    }
                    $enableLMHOSTS = $TcpIP.EnableLMHOSTS
                    if (!$enableLMHOSTS)
                    {
                        $enableLMHOSTS = $FALSE
                    }
                }
                try
                {
                    if (($netBiosOptions -eq 0) -or ($netBiosOptions -eq 1) -or ($netBiosOptions -eq 2))
                    {
                        $netBtId = "Tcpip_" + $netCfgInstanceId;
                        if (!(Test-Path -Path $netBTPath\$netBtId))
                        {
                             New-Item -Path $netBTPath -Name $netBtId
                        }
                        "Information - Restore the following netbiosOptions for interface $adapterName : $netBiosOptions" >> $logFile
                        Set-ItemProperty -Path $netBTPath\$netBtId -Name "NetbiosOptions" -Value $netBiosOptions -Type Dword -ErrorAction Stop;
                        if ($nameServerList)
                        {
                            "Information - Restore the following nameServerList for interface $adapterName : $nameServerList" >> $logFile
                            Set-ItemProperty -Path $netBTPath\$netBtId -Name "NameServerList" -Value $nameServerList -Type MultiString -ErrorAction Stop;
                        }
                    }
                    #$netAdapterClass = [wmiclass]'Win32_NetworkAdapterConfiguration'
                    #$netAdapterClass.EnableWINS($enableDNS, $enableLMHOSTS)
                } catch
                {
                    "ERROR - Failed to set NetbiosOptions to value " + $inter.NetBiosOptions.Value + " with error = " + $_.Exception.Message >> $logFile;
                    $errorStatus = $ERROR_SET_REG_KEY;
                }
                
                # Restore gateway and metric
                if($interfaceMetric -gt 0)
                {
                    try
                    {
                        "Information - Restore the following interface metric for interface $adapterName : $interfaceMetric" >> $logFile
                        Set-NetIPInterface –InterfaceIndex $index -InterfaceMetric $interfaceMetric
                    } catch
                    {
                        "Error - Failed to restore interafce metric = $interfaceMetric for interface $adapterName with error = " + $_ >> $logFile;
                    }
                }
                if ($defaultgateway)
                {
                    "Information - Restore the following default gateways for interface $adapterName : $defaultgateways" >> $logFile
                    "Information - Restore the following default gateway metrics for interface $adapterName : $defaultGateWayMetrics" >> $logFile
                    $result = $netInterface.SetGateways($defaultgateways, $defaultGateWayMetrics)
                    if ($result.ReturnValue -eq 0)
                    {
                        "Information - Set default gateways and metrics result = " + $result.ReturnValue >> $logFile
                    } else
                    {
                        "Error - Set default gateways and metrics result = " + $result.ReturnValue >> $logFile
                        $errorStatus = $ERROR_SET_IP_CONFIGURATION;
                    }
                } 
            } catch
            {
                "ERROR - Failed to set IP configuration for the interface " + $adapterName + " with error = " + $_ >> $logFile;
                $errorStatus = $ERROR_SET_IP_CONFIGURATION;
            }
        }
        # Restore the DNS server configuration.
        # We can also use the wmi object as above to restore DNS server.
        # (use SetDNSServerSearchOrder function).
        $nameServer = $TcpIP.NameServer -as [string];
        if ($nameServer -and ($index -ge 0))
        {
            "Information - Restore the following name server for interface $adapterName (Registery key = $tcpIPPath\$netCfgInstanceId) : $nameServer" >> $logFile
            for ($i = 0; $i -lt 3; $i++)
            {
                try
                {
                    Set-ItemProperty -Path $tcpIPPath\$netCfgInstanceId -Name "NameServer" -Value $nameServer -ErrorAction Stop;
                } catch
                {
                    if ($i -lt 2)
                    {
                        "Information - Failed to set DNS server for the interface " + $adapterName + " with error = " + $_ + " ,try again." >> $logFile;
                        continue;
                    } else
                    {
                        "ERROR - Failed to set DNS server for the interface " + $adapterName + " with error = " + $_ >> $logFile;
                        $errorStatus = $ERROR_SET_DNS_SERVER;
                    }
                }
                break;
            }
        }
        try
        {
            $domain = $TcpIP.Domain -as [string]
            if ($domain)
            {
                "Information - Restore the following domain for interface $adapterName : $domain" >> $logFile
                Set-ItemProperty -Path $tcpIPPath\$netCfgInstanceId -Name "Domain" -Value $domain -Type String -ErrorAction Stop;
            }
        } catch
        {
            "Information - Failed to set domain DNS server for the interface " + $adapterName + " with error = " + $_ >> $logFile;
        }
        try
        {
            $registrationEnabled = $TcpIP.RegistrationEnabled -as [string]
            if (($registrationEnabled -eq 0) -or ($registrationEnabled -eq 1))
            {
                "Information - Restore the following registration enabled for interface $adapterName : $registrationEnabled" >> $logFile
                Set-ItemProperty -Path $tcpIPPath\$netCfgInstanceId -Name "RegistrationEnabled" -Value $registrationEnabled -Type Dword -ErrorAction Stop;
            } else
            {
                "Information - Set the registration enabled for interface $adapterName to 0" >> $logFile
                Set-ItemProperty -Path $tcpIPPath\$netCfgInstanceId -Name "RegistrationEnabled" -Value 0 -Type Dword -ErrorAction Stop;
            }
            $registerAdapterName = $TcpIP.RegisterAdapterName -as [string]
            if (($registerAdapterName -eq 0) -or ($registerAdapterName -eq 1))
            {
                "Information - Restore the following registeration adapter name for interface $adapterName : $registerAdapterName" >> $logFile
                Set-ItemProperty -Path $tcpIPPath\$netCfgInstanceId -Name "RegisterAdapterName" -Value $registerAdapterName -Type Dword -ErrorAction Stop;
            }else
            {
                "Information - Set the registeration adapter name for interface $adapterName to 0" >> $logFile
                Set-ItemProperty -Path $tcpIPPath\$netCfgInstanceId -Name "RegisterAdapterName" -Value 0 -Type Dword -ErrorAction Stop;
            }
            
        } catch
        {
            "Information - Failed to set DNS server properties for the interface " + $adapterName + " with error = " + $_ >> $logFile;
        }
    }
    # TODO: 
    if ($TcpIP6)
    {
    
    }
    return $errorStatus;
}

function renameNewInterfaces($type, $backupCard)
{
    [xml]$xmlBackFile = [xml](Get-Content $filePath);
    $interfacesInstancesID = @($xmlBackFile.SelectNodes($interfacesPathInBackup) | Where {$_.LocationInfo -eq $backupCard.LocationInfo} | Where {$_.Type -eq $type});
    for ($i = 0; $i -lt $interfacesInstancesID.length; $i++)
    {
        $currName = $interfacesInstancesID[$i].Name;
        $crrNameExists = Get-NetAdapter | Where {$_.Name -eq $currName}
        $interIndex = 1;
        While ($crrNameExists -and ($interIndex -lt 15))
        {
            $tempName = $currName + "_" + $interIndex;
            try
            {
                Rename-NetAdapter -Name $currName -NewName $tempName -ErrorAction Stop;
            } catch
            {
                "Information - Failed to rename the new interface " + $currName + " with error = " + $_.Exception.Message >> $logFile;
                $interIndex = $interIndex + 1;
                if ($interIndex -eq 15)
                {
                    "Error - Tried 15 times and failed to rename the new interface " + $currName + " with error = " + $_.Exception.Message >> $logFile;
                }
            }
            $crrNameExists = Get-NetAdapter | Where {$_.Name -eq $currName}
        }
    }
}

# The function restore all the registry keys of the interfaces, also it restore all the network configuration.
#
# @param $backupCard - A handle to the xml node in the backup file that contains the data of the card we 
#                      want to restore the configuration of it's adapters.
# @param $type - The type of the interfaces we want to restore, it should be "IBA" or "MLX4".
# @param $cardName - The name of the card.
# @param $backupFile - A handle to the backup file.
function setInterafceConfiguration($backupCard, $type, $backupFile, $deviceID_t)
{
    $errorStatus = $ERROR_SUCCESS;
    if ($backupCard.$type)
    {
        try
        {
            waitForCardLoad $backupCard
			"Information - print list of network adapters before set configuration for device at Location  " + $backupCard.LocationInfo  >> $logFile
			#waiting for adapter load
			Start-Sleep -Seconds 2
			printNetAdapters
            
            switch ($type)
            {
                $IBA{
                    $path = $DEFAULT_HEADER_IB;
                    renameNewInterfaces "ib" $backupCard
                    setDevicePortsType $backupCard.LocationInfo "ib" "ib";
                    renameNewInterfaces "ib" $backupCard
                    $interfaces = @(Get-WmiObject Win32_PNPEntity -ErrorAction Stop | Where {$_.Service -Match "ipoib"});
                } 
                $MLX4 {
                    $path = $DEFAULT_HEADER_ETH;
                    renameNewInterfaces "eth" $backupCard
                    setDevicePortsType $backupCard.LocationInfo "eth" "eth";
                    renameNewInterfaces "eth" $backupCard
                    $interfaces = @(Get-WmiObject Win32_PNPEntity -ErrorAction Stop | Where {$_.Service -Match "eth"});
                }
                default {
                    "ERROR - Unknown interface type, type = " + $type >> $logFile;
                    return $ERROR_UNKNOWN_INTERFACE_TYPE;
                }
            }
			"Information - print list of network adapters ater rename of new interfaces for device at Location  " + $backupCard.LocationInfo >> $logFile
			printNetAdapters
        } catch
        {
            $ErrorMessage = "ERROR - Function setInterafceConfiguration failed for card with location information " + $backupCard.LocationInfo + "with error: " + $_.Exception.Message;
            $ErrorMessage >> $logFile;
            return $ERROR_EXCEPTION;
        }
        
        [xml]$defaultsFile = Get-Content $defaultsPath;
        foreach ($inter in $backupCard.$type.Interface)
        {
            $retry = 0;
            $interfaceFound = 0;
            "Information - Searching for interface with id = " + $inter.interfaceID >> $logFile;
            while (($retry -lt 30) -and ($interfaceFound -eq 0))
            {
                for ($i = 0; $i -lt $interfaces.length; $i++)
                {
                    $deviceID = @($interfaces[$i].deviceID -split "\\")[2];
                    $deviceID = @($deviceID -split "-")[0] + @($deviceID -split "-")[1];
                    "Information - Found interface with id = " + $deviceID >> $logFile;
                    if ($inter.interfaceID -eq $deviceID)
                    {
                        "Information - Interface with id = " + $inter.interfaceID + " found." >> $logFile;
                        $interfaceFound = 1;
                        $deviceID = $interfaces[$i].deviceID;
                        $instanceID = @(Get-ItemProperty -Path $pciPath\$deviceID).Driver;
                        foreach ($reg in $defaultsFile.RootElement.$path.RegKey)
                        {
                            $name = $reg.Name;
                            #$name = $name -replace "\*", "";
                            $BackupRegKey = ($inter.BasicConfiguration.RegKey | where {$_.Name -eq $name});
                            if ($BackupRegKey)
                            {
                                $valuesInBackup = $BackupRegKey.Value; 
                                $currDriverVersion = (Get-ItemProperty -Path $interfacesClass\$instanceID -Name "DriverVersion" -ErrorAction Stop).DriverVersion 
                                $oldDriverVersion = ($inter.BasicConfiguration.RegKey | where {$_.Name -eq "DriverVersion"}).Value;
                                $cmpOldVersions = cmpDriverVersion $oldDriverVersion $STAT_VERSION
                                $cmpNewVersions = cmpDriverVersion $currDriverVersion $STAT_VERSION
                                $cmpWIn2k12InbxVer = cmpDriverVersion $oldDriverVersion $WIN2K12INBX_VERSION
                                if (($name -match "JumboPacket") -and ($type -eq $MLX4) -and
                                    ($cmpOldVersions -lt 0) -and ($cmpNewVersions -ge 0) -and ($cmpWIn2k12InbxVer -ne 0))
                                {
                                    $valuesInBackup = 14 + ($valuesInBackup -as [int]);
                                }
                                if ($valuesInBackup -ne $reg.Default)
                                {
                                    try
                                    {
                                        Set-ItemProperty -Path $interfacesClass\$instanceID -Name $reg.Name -Value $valuesInBackup -Type String -ErrorAction Stop;    
                                    } catch 
                                    {
                                        "ERROR - Failed to set registry key " + $reg.Name + " to value " + $valuesInBackup + " with error = " + $_.Exception.Message >> $logFile;
                                        $errorStatus = $ERROR_SET_REG_KEY;
                                    }
                                }
                            }
                        }
                        
                        # Restore the name of the interface.
                        $newAdapterName = @(Get-NetAdapter -ErrorAction Stop | Where {$_.InterfaceDescription -eq $interfaces[$i].Name}).Name;
                        $oldAdapterName = $inter.Name -as [String];
						"Information - print list of network adapters before rename"  >> $logFile
						printNetAdapters
                        try
                        {    
                            if ($newAdapterName -ne $oldAdapterName)
                            {
                                $oldNameExists = (Get-NetAdapter -ErrorAction Stop | Where {$_.Name -eq $oldAdapterName});
                                if ($oldNameExists)
                                {
									
                                    $tempName = $oldAdapterName + "_";
									"Information - old adapter $oldAdapterName exists changing it name to $tempName  " >> $logFile
                                    Rename-NetAdapter -Name $oldAdapterName -NewName $tempName -ErrorAction Stop;
                                }
								"Information - renaming $newAdapterName to $oldAdapterName" >> $logFile
                                Rename-NetAdapter -Name $newAdapterName -NewName $oldAdapterName -ErrorAction Stop;
                            }
                            
                            # Restore TcpIP configuration.
                            $result = restoreNetworkConfiguration $inter.TcpIP $inter.TcpIP6 $oldAdapterName $instanceID;
                            if ($result.SyncRoot)
                            {
                                $err = $result.SyncRoot[$result.length - 1];
                            } else
                            {
                                $err = $result;
                            }
                            if ($err -ne $ERROR_SUCCESS)
                            {
                                $errorStatus = $err;
                            }
                        } catch
                        {
                            "ERROR - Failed to rename the interface $newAdapterName to $oldAdapterName with error = " + $_.Exception.Message >> $logFile;
                            $errorStatus = $ERROR_SET_NAME;
                        }
                        break;
                    }
                    
                }
                if ($interfaceFound -eq 0)
                {
                    $retry = $retry + 1;
                    if ($retry -lt 30)
                    {
                        "Information - Interface with id = " + $inter.interfaceID + " is missing, trying again." >> $logFile;
                        Start-Sleep -s 1
                        try
                        {
                            switch ($type)
                            {
                                $IBA{
                                    $interfaces = @(Get-WmiObject Win32_PNPEntity -ErrorAction Stop | Where {$_.Service -Match "ipoib"});
                                } 
                                $MLX4 {
                                    $interfaces = @(Get-WmiObject Win32_PNPEntity -ErrorAction Stop | Where {$_.Service -Match "eth"});
                                }
                                default {
                                    "Information - Unknow interface type." >> $logFile
                                }
                            }
                        } catch
                        {
                            $ErrorMessage = "ERROR - Function setInterafceConfiguration failed for card with location information " + $backupCard.LocationInfo + "with error: " + $_.Exception.Message;
                            $ErrorMessage >> $logFile;
                            return $ERROR_EXCEPTION;
                        }
                        "Information - The following interfaces are up : " + $interfaces >> $logFile
                    } else
                    {
                        "Error - Interface with id = " + $inter.interfaceID + " is missing." >> $logFile;
                        $errorStatus = $ERROR_INTERFACE_MISSING;
                    }
                }
            }
        }
        
        # Restore IPoIBP adapters.
        if ($backupCard.$type.IPOIBP)
        {
            foreach ($ipoibpInter in $backupCard.$type.IPOIBP.Interface)
            {
                try
                {
                    try
                    {
                        $localName = $localConnection.Name
                        $localAdapterUp = (Get-NetAdapter | Where {$_.Name -eq $localName})
                        if (!$localAdapterUp)
                        {
                            setDevicePortsType $backupCard.LocationInfo "ib" "ib"; 
                        }
                    } catch
                    {
                        $ErrorMessage = "ERROR - Function setInterafceConfiguration failed for card  with location information " + $backupCard.LocationInfo + "with error: " + $_.Exception.Message;
                        $ErrorMessage >> $logFile;
                        return $ERROR_EXCEPTION; 
                    }
                    $partManPath = Join-Path (Join-Path (Join-Path $installDir "IB") "Tools") "part_man"
                    $localConnection = $backupFile.RootElement.BackupConfiguration.Inter | Where {$_.Guid -match $ipoibpInter.interfaceID};
                    "Create new virtual IPoIB port " + $ipoibpInter.LocalName + " to physical port " + $localConnection.Name >> $logFile
                    &$partManPath add $localConnection.Name $ipoibpInter.LocalName >> $logFile
                    
                    $newName = @(@(&$partManPath show | Select-String $ipoibpInter.LocalName) -split "  ")[0] -as [String];
                    $ipoibCounter = 0;
                    while (!$newName -and ($ipoibCounter -lt 15))
                    {
                        "Information - Virtual IPoIB interface " + $ipoibpInter.LocalName + " is missing, waiting to link up." >> $logFile
                        Start-Sleep -S 1
                        $newName = @(@(&$partManPath show | Select-String $ipoibpInter.LocalName) -split "  ")[0] -as [String];
                        $ipoibCounter++
                    }
                    if ($newName)
                    {
                        "Information - Virtual IPoIB interface " + $ipoibpInter.LocalName + " Found." >> $logFile
                    } else
                    {
                        "Error - Virtual IPoIB interface " + $ipoibpInter.LocalName + " is missing." >> $logFile
                    }
                    $oldName = $ipoibpInter.Name -as [String];
                } catch
                {
                    "Error - Failed to add virtual IPoIB port " + $ipoibpInter.LocalName + " to physical port " + $localConnection.Name + " with error = " + $_.Exception.Message >> $logFile
                    $errorStatus = $ERROR_ADD_V_ADAPTER
                    continue
                }
                
                try
                {
                    Rename-NetAdapter -Name $newName -NewName $oldName -ErrorAction Stop;
                } catch
                {
                    "ERROR - Failed to rename the virtual interface " + $oldAdapterName + " with error = " + $_.Exception.Message >> $logFile;
                    $errorStatus = $ERROR_SET_NAME;
                    continue
                }
                
                $deviceID = @(Get-WmiObject Win32_PNPEntity | Where {$_.DeviceID -match $ipoibpInter.LocalName}).DeviceID;
                $instanceID = @(Get-ItemProperty -Path $pciPath\$deviceID).Driver;
                foreach ($reg in $defaultsFile.RootElement.$path.RegKey)
                {
                    $name = $reg.Name;
                    #$name = $name -replace "\*", "";
                    $valuesInBackup = ($ipoibpInter.BasicConfiguration.RegKey | where {$_.Name -eq $name}).Value; 
                    $currDriverVersion = (Get-ItemProperty -Path $interfacesClass\$instanceID -Name "DriverVersion").DriverVersion 
                    $oldDriverVersion = ($inter.BasicConfiguration.RegKey | where {$_.Name -eq "DriverVersion"}).Value;
                    $cmpOldVersions = cmpDriverVersion $oldDriverVersion $STAT_VERSION
                    $cmpNewVersions = cmpDriverVersion $currDriverVersion $STAT_VERSION
                    $cmpWIn2k12InbxVer = cmpDriverVersion $oldDriverVersion $WIN2K12INBX_VERSION
                    # We should add 14 to the JumboPacket property only when upgrading from  version that are older than 4.40 in win2012/2008 R2.
                    # In win2012 R@ the inbox version is 4.4 and no need to add 14 to the JumboPacket property
                    if (($name -match "JumboPacket") -and ($type -eq $MLX4) -and
                        ($cmpOldVersions -lt 0) -and ($cmpNewVersions -ge 0)  -and ($cmpWIn2k12InbxVer -ne 0))
                    {
                        $valuesInBackup = 14 + ($valuesInBackup -as [int]);
                    }
                    if ($valuesInBackup -ne $reg.Default)
                    {
                        try
                        {
                            Set-ItemProperty -Path $interfacesClass\$instanceID -Name $reg.Name -Value $valuesInBackup -Type String -ErrorAction Stop;
                        } catch 
                        {
                            "ERROR - Failed to set registry key " + $reg.Name + " to value " + $valuesInBackup + " with error = " + $_.Exception.Message >> $logFile;
                            $errorStatus = $ERROR_SET_REG_KEY;
                        }
                    }
                }
                # Restore TcpIP configuration.
                $result = restoreNetworkConfiguration $inter.TcpIP $inter.TcpIP6 $oldName $instanceID;
                if ($result.SyncRoot)
                {
                    $err = $result.SyncRoot[$result.length - 1];
                } else
                {
                    $err = $result;
                }
                if ($err -ne $ERROR_SUCCESS)
                {
                    $errorStatus = $err;
                }
            }
        }
    }
    return $errorStatus;
}
function parseLocationInfo($locInfo)
{
    $rawLocationInfo = $locInfo -replace "PCI Bus" , ""
    $rawLocationInfo = $rawLocationInfo -replace "device" , ""
    $rawLocationInfo = $rawLocationInfo -replace "function" , ""
    $rawLocationInfo = $rawLocationInfo -replace " " , ""
    $locationInfoArray = $rawLocationInfo -split ","
    "Information - parseLocationInfo: Location information string is $locInfo parsed location is $rawLocationInfo" >> $logFile
    return $locationInfoArray
}

# The function sets the ports type of the device of the given adapter. 
#
# @param $netAdapterName - The name of the adapter we want to set it's device.
# @param $port1Type - The type of the first port of the device.
# @param $port2Type - The type of the second port of the device.
function setDevicePortsType ($cardLocationInfo, $port1Type, $port2Type)
{
    [xml]$defaultFile_t = Get-Content $defaultsPath;
    $cards = $defaultFile_t.SelectNodes($cardsPathInBackup);
    $neededCard = ($cards | Where {$_.LocationInfo -eq $cardLocationInfo});
    "Information - cards location info: $cardLocationInfo" >> $logFile
    $instanceID = $neededCard.DriverID;
    $pnpDriverID = $neededCard.PNPDriverID;
    if ($neededCard)
    {
        $newPortsType = $port1Type + "," + $port2Type;
        $currPortsType = (Get-ItemProperty -Path $interfacesClass\$instanceID\"Parameters").PortType
        if ($currPortsType -ne $newPortsType)
        {
            $adaptersCount = (Get-NetAdapter | Where {$_.InterfaceDescription -match "Mellanox"} | measure).Count
            "Information - $adaptersCount Mellanox adapters are up before restart." >> $logFile
            Set-ItemProperty -Path "$interfacesClass\$instanceID\Parameters" -Name PortType -Value $newPortsType -Type String;
            $locationInfoArray = parseLocationInfo $cardLocationInfo
            $resRestart = restartCard $pnpDriverID $locationInfoArray  ;
            if ($resRestart -ne $ERROR_SUCCESS)
            {
                return $resRestart;
            }
            $retry = 0
            $newAdaptersCount = (Get-NetAdapter | Where {$_.InterfaceDescription -match "Mellanox"} | measure ).Count
            while (($adaptersCount -gt $newAdaptersCount) -and ($retry -lt 30))
            {
                "Information - Only $newAdaptersCount Mellanox adapters are up after restart, wait 1 second." >> $logFile
                Start-Sleep -Seconds 1
                $newAdaptersCount = (Get-NetAdapter | Where {$_.InterfaceDescription -match "Mellanox"} | measure).Count
                $retry++
            }
            if ($adaptersCount -gt $newAdaptersCount)
            {
                "Information - Not all Mellanox adapters went up after restart." >> $logFile
            }
        }
    } else
    {
        "Error - setDevicePortsType failed with error = missing card, card with location inforamation = " + $cardLocationInfo >> $logFile;
        return $ERROR_CARD_MISSING;
    }
    return $ERROR_SUCCESS;
}

# The function restores the configuration of the teams.
#
# @param $backupTeams - A hanlde to the xml node in the backup file that contains the 
#                       configuration of the teams.
function restoreTeams($backupTeams)
{
    "Start restore Teaming configuration." >> $logFile;
    foreach ($team in $backupTeams.Team)
    {
        foreach ($member in $team.Member)
        {
            $memberName = $member.'#text'
            $adapterUp = (Get-NetAdapter | Where {$_.Name -eq $memberName})
            if (!$adapterUp)
            {
                $memberLocationInfo = getLocationInfo $member.'#text';
                setDevicePortsType $memberLocationInfo $member.Type $member.Type;
            }
            try {
                $teamsName = @(Get-NetLbfoTeam -ErrorAction Stop).Name;
                if ($teamsName -and $teamsName.Contains($team.Name))
                {
                    Add-NetLbfoTeamMember -Name $member.'#text' -Team $team.Name -Confirm:$false -ErrorAction Stop;
                } else
                {
                    New-NetLbfoTeam -Name $team.Name -TeamMembers $member.'#text' -TeamingMode $team.TeamingMode -LoadBalancingAlgorithm $team.LoadBalancingAlgorithm -Confirm:$false -ErrorAction Stop;
                }
            } catch
            {
                "ERROR - Failed to add member " + $member.'#text' + " to team " + $team.Name + " with error = " + $_.Exception.Message >> $logFile;
                return $ERROR_EXCEPTION;
            }
        }
        $teamNics = $team.TeamNic;
        foreach ($teamNic in $teamNics)
        {
            if ($team.Name -ne $teamNic.Name)
            {
                try
                {
                    Add-NetLbfoTeamNic -Team $team.Name -VlanID $teamNic.VlanId -Name $teamNic.Name -Confirm:$false -ErrorAction Stop;
                } catch
                {
                    "ERROR - Failed to add team NIC " + $teamNic.Name + " to team " + $team.Name + " with error = " + $_.Exception.Message >> $logFile;
                    return $ERROR_EXCEPTION;
                }
            }
            try
            {
                $configurationRestored = 0
                $currentTeamInReg = @((Get-ChildItem -Path $teamsPath -ErrorAction Stop | Get-ItemProperty).Driver);
                for ($i = 0; $i -lt $currentTeamInReg.length; $i++)
                    {
                    $pnpInstanceId_d = $currentTeamInReg[$i];
                    $itemProperties = (Get-ItemProperty -Path $interfacesClass\$pnpInstanceId_d -ErrorAction Stop);
                    $netCfgInstanceId = $itemProperties.NetCfgInstanceId;
                    $name = (Get-ItemProperty -Path $networkPath\$netCfgInstanceId\Connection -ErrorAction Stop).Name;
                    if ($teamNic.Name -eq $name)
                    {
                        $configurationRestored = 1
                        restoreNetworkConfiguration $teamNic.TcpIP $teamNic.TcpIP6 $teamNic.Name $pnpInstanceId_d;
                    }
                }
                if ($configurationRestored -eq 0)
                {
                    "Error - Failed to restore network configuration of team " + $teamNic.Name + " because it is not found." >> $logFile
                }
            } catch
            {
                "Error - Failed to restore network configuration of team " + $teamNic.Name + " with error = " + $_.Exception.Message >> $logFile;
            }
        }
    }
    "Finished restore Teaming configuration." >> $logFile;
    return $ERROR_SUCCESS;
}

# The function removes ND provider that installed in the new driver version although it was not installed in the old one. 
#
# @param $ndProvider - the nd provider in the new version.
# @param $oldNDProviders - the ND provider was installed in the old version.
# @param $testedProvider -  the name of the provider we want to remove.
function removeNDProvider ($ndProvider, $oldNDProviders, $testedProvider)
{
    if ($ndProvider -and !($oldNDProviders.Contains($testedProvider)))
    {                
        ndinstall -r $testedProvider >> $logFile;
    }
}

# The function restores the ND-Providers were installed before the upgrade.
#
# @param $ndProviders - A hanlde to the xml node in the backup file that contains the 
#                       installed nd-providers.
function restoreNDProviders($ndProviders)
{
    "Start restoring ND-Providers." >> $logFile;
    $ndInstallInstalled = @(get-command -type Application | Where {$_.Name -Match "ndinstall"});
    if ($ndInstallInstalled)
    {
        foreach ($provider in $ndProviders.Provider)
        {
            ndinstall -i $provider.Name >> $logFile;
        }
        $ndv1 = ndinstall | Select-String "NDv1";
        $ndv2 = ndinstall | Select-String "NDv2";
        $ibal = ndinstall | Select-String "OpenFabrics Network Direct Provider";
        
        $oldNDProviders = @($ndProviders.Provider.Name);
        removeNDProvider $ndv1 $oldNDProviders $MLX4ND;
        removeNDProvider $ndv2 $oldNDProviders $MLX4ND2;
        removeNDProvider $ibal $oldNDProviders $IBAL;
    } else
    {
        "ndinstall.exe is not found." >> $logFile;
    }
    "Finished restoring ND-Providers." >> $logFile;
}

# The function restores the configuration of the vSwitches.
#
# @param $vSwitches - A hanlde to the xml node in the backup file that contains the 
#                     the data of the vSwitches.
function restoreHyperVConfig($vSwitches)
{
    $err = $ERROR_SUCCESS;
    "Start restoring Hyper-V configuration." >> $logFile;
    foreach ($switch in $vSwitches.Switch)
    {
        try {
            $memberName = $switch.NetAdapter
            $adapterUp = (Get-NetAdapter | Where {$_.Name -eq $memberName})
            if (!$adapterUp)
            {
                $memberLocationInfo = getLocationInfo $switch.NetAdapter;
                setDevicePortsType $memberLocationInfo $switch.NetAdapterType $switch.NetAdapterType;
            }
            Set-VMSwitch $switch.Name -SwitchType Private -ErrorAction Stop;
            Set-VMSwitch $switch.Name -NetAdapterName $switch.NetAdapter -ErrorAction Stop;
        } catch
        {
            "ERROR - Failed to connect switch " + $switch.Name + " with error = " + $_.Exception.Message >> $logFile;
            $err =  $ERROR_EXCEPTION;
        }
    }
    "Finished restoring Hyper-V configuration." >> $logFile;
    return $err;
}

# The function restores the configuration of the performance tuning.
#
# @param $vSwitches - A hanlde to the xml node in the backup file that contains the 
#                     scenario were run before the upgrade.
function restorePerformanceTuning($backupTuningCinfig)
{
    "Start restoring performance tuning configuration." >> $logFile;
    $adaptersDone = @();
    foreach ($scenario in $backupTuningCinfig.ScenarioTuning)
    {
        if (!($adaptersDone.Contains($scenario.AdapterName)))
        {
            if (($scenario.Scenario -eq $SINGLE_PORT_STREAM) -or 
                ($scenario.Scenario -eq $SINGLE_STREAM) -or
                ($scenario.Scenario -eq $MCAST_STREAM))
            {
                $adapterName = $scenario.AdapterName
                $adapterUp = (Get-NetAdapter | Where {$_.Name -eq $adapterName})
                if (!$adapterUp)
                {
                    $memberLocationInfo = getLocationInfo $scenario.AdapterName;        
                    setDevicePortsType $memberLocationInfo $scenario.adapterType $scenario.adapterType;
                }
                switch ($scenario.Scenario)
                {
                    $SINGLE_PORT_STREAM {perf_tuning.exe -s -c1 $scenario.AdapterName >> $logFile}
                    $SINGLE_STREAM {perf_tuning.exe -st -c1 $scenario.AdapterName >> $logFile}
                    $MCAST_STREAM {perf_tuning.exe -mc -c1 $scenario.AdapterName >> $logFile}
                }
                $adaptersDone = $adaptersDone + $scenario.AdapterName;
            } else
            {
                # In dual port stream and forwarding stream we have to find the second adapter.
                $secondAdapter = $backupTuningCinfig.ScenarioTuning | Where {($_.LocationInfo -eq $scenario.LocationInfo) -and 
                                                                             ($_.AdapterName -ne $scenario.AdapterName) -and
                                                                             ($_.Scenario -eq $scenario.Scenario)};
                $secondAdapterType = $secondAdapter.adapterType;
                $firstAdapterUp = (Get-NetAdapter | Where {$_.Name -eq $scenario.AdapterName})
                $secondAdapterUp = (Get-NetAdapter | Where {$_.Name -eq $secondAdapter.AdapterName})
                if (!$firstAdapterUp -or !$secondAdapterUp)
                {
                    $memberLocationInfo = getLocationInfo $scenario.AdapterName;
                    setDevicePortsType $memberLocationInfo $scenario.adapterType $secondAdapterType;
                    $neededConfig = Get-NetAdapter | Where {$_.Name -eq $scenario.AdapterName};
                    if (!$neededConfig)
                    {
                        $memberLocationInfo = getLocationInfo $scenario.AdapterName;
                        setDevicePortsType $memberLocationInfo $secondAdapterType $scenario.adapterType;
                    }
                }
                switch ($scenario.Scenario)
                {
                    $DUAL_PORT_STREAM {
                         perf_tuning.exe -d -c1 $scenario.AdapterName -c2 $secondAdapter.AdapterName >> $logFile;
                    } 
                    $FORWARDING_STREAM {
                        perf_tuning.exe -f -c1 $scenario.AdapterName -c2 $secondAdapter.AdapterName >> $logFile;
                    }
                    default {
                        "ERROR - Unsupported scenario tuning, scenario = " + $scenario.Scenario >> $logFile;
                    }
                }    
                $adaptersDone = $adaptersDone + $scenario.AdapterName;
                $adaptersDone = $adaptersDone + $secondAdapter.AdapterName;
            }
        }
    }
    "Finished restoring performance tuning configuration." >> $logFile;
}

# The function retrieve the ports configuration of the cards saved in the backup file, and then
# it restart them
#
# @param $cards - A handle to the connected cards in the machine, we can get them by using
#                 the command "Get-MlnxPCIDeviceSetting".
# @param $backupCards - A xml handle to the cards in the backup file.
function restartCards($cards, $backupCards)
{
    foreach ($card in $backupCards)
    {
        for ($i = 0; $i -lt $cards.length; $i++)
        {
            $deviceID = $cards[$i].PNPDeviceID;
            $deviceProperty = @(Get-ItemProperty -Path $pciPath\$deviceID);
            $locationInfo_t = $deviceProperty.LocationInformation -split "\(";
            $locationInfo = $locationInfo_t[1];
            $locationInfo = $locationInfo -replace "\(", "";
            $locationInfo = $locationInfo -replace "\)", "";
            $locationInfo = $locationInfo -split ",";
            $locationInfo = "PCI bus " + $locationInfo[0] + ", " + "device " + $locationInfo[1] + ", " + "function " + $locationInfo[2];
            if ($card.LocationInfo -eq $locationInfo) {
                $driver = $deviceProperty.Driver;
                if ($card.PortType)
                {
                    Set-ItemProperty -Path $interfacesClass\$driver\"Parameters" -Name PortType -Value $card.PortType -Type String;
                } else
                {
                    $portsType = (Get-ItemProperty -Path $interfacesClass\$driver\"Parameters").PortType
                    if ($portsType)
                    {
                        Remove-ItemProperty -Path $interfacesClass\$driver\"Parameters" -Name PortType
                    }
                }
                $resRestart = restartCard $deviceID @();
                if ($resRestart -ne $ERROR_SUCCESS)
                {
                    "Error - Failed to restart device with id " + $deviceID + " with error = " + $resRestart >> $logFile;
                }
            }
        }
    }
}

# The function adds a node called "Card" to given file under the "RootElement" node,
# and sets the location information and the card name as attributes.
#
# @param $cardName - The name of the card.
# @param $locationInfo - The location information of the card.
# @param $filePath_t - Path of the file we want to add the node to.
function addCardToFile ($locationInfo, $filePath_t, $driverID, $deviceID)
{
    [xml]$file = Get-Content $filePath_t;
    $rootElement = $file.selectSingleNode($rootElement);
    $card = $file.createElement("Card");
    $card.setAttribute("LocationInfo", $locationInfo);
    $card.setAttribute("DriverID", $driverID);
    $card.setAttribute("PNPDriverID", $deviceID);
    $rootElement.AppendChild($card);
    $file.save($filePath_t);
}

function getRoceModeByOldParam($card)
{
    $newRoceMode = $NO_ROCE_MODE;
    if ($card.Roce)
    {
        $newRoceMode = $card.Roce.roce_mode;
    } else
    {
        if ($card.EnableRoce)
        {
            if ($card.EnableRoce -match "1")
            {
                $newRoceMode = $ROCE_MODE;
            }
        }
        if ($card.EnableRRoce)
        {
            if ($card.EnableRRoce -match "1")
            {
                $newRoceMode = $RROCE_OVER_UDP_MODE;
            }
        }
    }
    return $newRoceMode;
}
function getDriverRoceMode($cards, $roce)
{
    $newMode = $NO_ROCE_MODE;
    if ($roce.roce_mode)
    {
        $newMode = $roce.roce_mode;
    } else
    {
        foreach ($card in $cards)
        {
            $temp = getRoceModeByOldParam $card;
            if (($temp -ne $NO_ROCE_MODE) -and (($temp -gt $newMode) -or ($newMode -eq $NO_ROCE_MODE)))
            {
                $newMode = $temp;
            }
        }
    }
    return $newMode;
}

# The function restores the configuration of DNS suffixes configuration.
# Not used since the DNS suffixes are global and no need to restore them.
#
# @param $backupDNSSuffixes - DNS suffixes configuration in backup xml file.
function restoreDNSSuffixesConfig($backupDNSSuffixes)
{
    try
    {
        $searchList = $backupDNSSuffixes.SearchList -as [string]
        if ($searchList)
        {
            Set-ItemProperty -Path $tcpIPParametersPath -Name "SearchList" -Value $searchList -Type String -ErrorAction Stop;
        }
        $useDomainNameDevolution = $backupDNSSuffixes.UseDomainNameDevolution
        Set-ItemProperty -Path $tcpIPParametersPath -Name "UseDomainNameDevolution" -Value $useDomainNameDevolution -Type Dword -ErrorAction Stop;    
    } catch
    {
        "Error - Failed to restore the configuration of DNS suffixes with error = " + $_.Exciption.Message >> $logFile;
    }
}
#########################################################################
#########################################################################

# The function prints the usage of the tool.
function printUsage()
{
    Write-Host "Usage:"
    Write-Host "Tenable-Upgrade.exe -Operation <b | r | h> -Path [string] -ConnectXProOnly <0 | 1>  -EraseFiles <0 | 1> -RestartAppPath [string] -ExecutionMode <1 | 2>  -EthInfPath [string] -IbInfPath [string] "
    Write-Host;
    Write-Host "Where:"
    Write-Host "b, backup - Backs up the configuration."
    Write-Host "r, restore - Restores the configuration."
    Write-Host "h, help - Shows this text."
    Write-Host "ConnectXProOnly - Indicates the types of cards the tool can be used for."    
    Write-Host "                  0 value - Run the tool for all cards."    
    Write-Host "                  1 value - Run the tool only for all ConnectX-3 Pro cards."
    Write-Host "EraseFiles - [Optional, default value is 0] Enables backup files removal upon completion of the configuration restoration."
    Write-Host "             0 value - Do not remove the files."    
    Write-Host "             1 value - Remove the files."
    Write-Host "Path - [Optional, default value C:\Users\Administrator\AppData\Local] Indicates the location path where files can be saved."
    Write-Host "RestartAppPath - [Optional] Indicates the location path where the restart Mellanox driver tool is placed."
    Write-Host "                 In case the tool was run without this parameter, the restart driver tool should be placed" 
    Write-Host "                 in the same folder of the tool Tenable-Upgrade.exe"   
    Write-Host "InstallDir - Indicates the location path where the package is installed"
    Write-Host "                 In case the tool was run without this parameter, the parameter will be set to $DefaultInstallDir "
    Write-Host "ExecutionMode  - [Optional, default value is 1] define whether we are running as part of the WinOF package or not." 
    Write-Host "                 1 - WinOF package mode."
    Write-Host "                 2 - Standalone mode."
    Write-Host "EthInfPath - [Optional] The path to the folder of Ethernet INF file, user should set this argument when execution mode is standalone."
    Write-Host "             By default the value will be the installation folder."
    Write-Host "IbInfpath -  [Optional] The path to the folder of IPoIB INF file, user should set this argument when execution mode is standalone."
    Write-Host "             By default the value will be the installation folder."
}

# The function remve given file.
#
# @param $file - the path of the file we want to remove.
function removeFile($file)
{
    If (Test-Path $file)
    {
        Remove-Item -Path $file;
    }
}

# The function prints a given error.
#
# @param $error - An error to print.
function printError($error)
{
    switch($error)
    {
        $ERROR_SUCCESS {
            Write-Host "Success"
        }
        $ERROR_EXCEPTION {
            Write-Host "Error exception"
        }
        $ERROR_NO_CARDS {
            Write-Host "Error no Mellanox cards"
        }
        $ERROR_UNKNOWN_INTERFACE_TYPE {
            Write-Host "Error unknown interface type"
        }
        $ERROR_FILE_MISSING {
            Write-Host "Error file is missing"
        }
        $ERROR_CARD_MISSING {
            Write-Host "Error card is missing"
        }
        $ERROR_SET_REG_KEY {
            Write-Host "Error set registry key failed"
        }
        $ERROR_SET_NAME {
            Write-Host "Error set interafce name failed"
        }
        $ERROR_SET_IP_CONFIGURATION {
            Write-Host "Error set IP failed"
        }
        $ERROR_SET_DNS_SERVER {
            Write-Host "Error set DNS server failed"
        }
        $ERROR_BAD_INPUT {
            Write-Host "Error bad input"
        }
        $ERROR_INTERFACE_MISSING {
            Write-Host "Error interface is missing"
        } 
        $ERROR_ADD_V_ADAPTER {
            Write-Host "Error add new virtual IPoIB port"
        }
        default {
            Write-Host "Unknow error=$error";
        }
    }
}
#########################################################################

Switch ($Operation)
{
    # Backup the configuration.
    {($_ -eq "b") -or ($_ -eq "backup")} {
        Write-Host "The log file will be saved in $selectedPath."
        removeFile($filePath);
        removeFile($logFile);
        if (($ConnectXProOnly -ne 0) -and ($ConnectXProOnly -ne 1))
        {
            Write-Host "ERROR - Bad value for ConnectXProOnly, see usage."
            "ERROR - Bad value for ConnectXProOnly, see usage." >> $logFile;
            exit $ERROR_BAD_INPUT;
        }
        "#########################################################################" >> $logFile;
        if ($ConnectXProOnly -eq 1)
        {
            "Start Backing up the configuration only for ConnectX-3 Pro cards." >> $logFile;
        } else
        {
            "Start Backing up the configuration." >> $logFile;
        }
        
        $errorStatus = $ERROR_SUCCESS;
        try 
        {
            $cards = @(Get-WmiObject Win32_PNPEntity -ErrorAction Stop | Where {$_.PNPDeviceID -Match $MLNX_VEN_ID});
        }
        catch
        {
             $ErrorMessage = "ERROR - Function Get-WmiObject failed with error: " + $_.Exception.Message;
            Write-Host $ErrorMessage;
            $ErrorMessage >> $logFile;
            exit $ERROR_EXCEPTION;
        }
        
        If ($cards.length -eq 0)
        {
            $ErrorMessage =  "ERROR - No Mellanox Cards.";
            Write-Host $ErrorMessage;
            $ErrorMessage >> $logFile;
            exit $ERROR_NO_CARDS;
        }
        "Found " + $cards.length + " Mellanox cards." >> $logFile;
        $getDriverVersion = 0;
        $driverVersion = 0;
        $XmlWriter = New-Object System.Xml.XmlDocument;
        $root = $XmlWriter.CreateElement("RootElement");
        $BackupConfiguration = $XmlWriter.CreateElement("BackupConfiguration");
        $root.AppendChild($BackupConfiguration);
        $XmlWriter.AppendChild($root);
        
        # Backup the configuration of the devices.
        for ($i = 0; $i -lt $cards.length; $i++)
        {
            $name = $cards[$i].Description;
            
            $instanceId = $cards[$i].DeviceID;
            $driver = @(Get-ItemProperty -Path $pciPath\$instanceId);
            $driverId = $driver.Driver;
            $NICConfig = Get-ItemProperty -Path $interfacesClass\$driverId\Parameters;
            if ($getDriverVersion -eq 0)
            {
                $driverVersion = @(Get-ItemProperty -Path $interfacesClass\$driverId).DriverVersion;
                $BackupConfiguration.SetAttribute("revisionID", $driverVersion);
                $getDriverVersion = 1;
            }
            
            try 
            {
                $cardType = ((($instanceId -split "\\")[1] -split "_")[2] -split "&")[0];
                # We save the configuration only when major upgrade is needed.
                if (($ConnectXProOnly -eq 0) -or
                    (($ConnectXProOnly -eq 1) -and ($cardType -eq $CONNECTX_PRO_ID)))
                {
                    $locationInfo_t = $driver.LocationInformation -split "\(";
                    $locationInfo = $locationInfo_t[1];
                    $locationInfo = $locationInfo -replace "\(", "";
                    $locationInfo = $locationInfo -replace "\)", "";
                    $locationInfo = $locationInfo -split ",";
                    $locationInfo = "PCI bus " + $locationInfo[0] + ", " + "device " + $locationInfo[1] + ", " + "function " + $locationInfo[2];
                    $card = $XmlWriter.CreateElement("NIC");
                    $card.SetAttribute("Name", $name);
                    $card.SetAttribute("LocationInfo", $locationInfo);
                    $BackupConfiguration.AppendChild($card);
                    # Save the ports type configuration.
                    if (Test-Path $interfacesClass\$driverId\Parameters\Roce)
                    {
                        $roce = Get-ItemProperty -Path $interfacesClass\$driverId\Parameters\Roce -ErrorAction Stop;
                        
                        $newRoce = $XmlWriter.CreateElement("Roce");
                        addXmlNode $newRoce "roce_mode" $roce.roce_mode;
                        $card.AppendChild($newRoce);
                    }
                    
                    for ($j = 0; $j -lt  $DEVICE_CONFIGURATION_VARIABLES.length; $j++)
                    {
                        $var =  $DEVICE_CONFIGURATION_VARIABLES[$j];
                        if ($NICConfig.$var)
                        {
                            $str = $NICConfig.$var -as [string];
                            addXmlNode $card $var $str;
                        }
                    }

                    If ($BackupRoceMode -eq 1)
                    {
                        for ($j = 0; $j -lt  $OPTIONAL_DEVICE_CONFIGURATION_VARIABLES.length; $j++)
                        {
                         $var =  $OPTIONAL_DEVICE_CONFIGURATION_VARIABLES[$j];
                         if ($NICConfig.$var)
                            {
                               $str = $NICConfig.$var -as [string];
                             addXmlNode $card $var $str;
                            }
                        }
                    }
                    
                    If ((Test-Path $ipoibInterafcesPath))
                    {
                        $result = getAdapters $locationInfo $card "IPoIB" $ConnectXProOnly;
                        if ($result.SyncRoot)
                        {
                            $err = $result.SyncRoot[$result.length - 1];
                        } else
                        {
                            $err = $result;
                        }
                        if ($errorStatus -eq $Error_SUCCESS)
                        {
                            $errorStatus = $err;
                        }
                    }
                    If (Test-Path $ethInterafcesPath)
                    {
                        $result = getAdapters $locationInfo $card "ETH" $ConnectXProOnly;
                        if ($result.SyncRoot)
                        {
                            $err = $result.SyncRoot[$result.length - 1];
                        } else
                        {
                            $err = $result;
                        }
                        if ($errorStatus -eq $Error_SUCCESS)
                        {
                            $errorStatus = $err;
                        }
                    }
                    
                }
            } catch
            {
                $ErrorMessage =  "ERROR - Failed to get the configuration for card " + $cards[$i].Description + ", error = " + $_.Exception.Message;
                $ErrorMessage >> $logFile;
            }
        }
        
        # Save roce mode.
        If ($BackupRoceMode -eq 1)
        {
            if (Test-Path $roceModePath)
            {
                $roce = Get-ItemProperty -Path $roceModePath;

                $newRoce = $XmlWriter.CreateElement("Roce");
                addXmlNode $newRoce "roce_mode" $roce.roce_mode;
                $BackupConfiguration.AppendChild($newRoce);
            }
        }
        
        # Save the ND installed ND providers.
        backupNDProviders;
        $XmlWriter.Save($filePath);
        
        if ($SupportHVT -eq 1)
        {    
            # Save the teams.
            $result = backupTeams;
            if ($result.SyncRoot)
            {
                $err = $result.SyncRoot[$result.length - 1];
            } else
            {
                $err = $result;
            }
            if ($err -ne $ERROR_SUCCESS)
            {
                $errorStatus = $err;
            }
            $XmlWriter.Save($filePath);
                
            # Save the configuration of Hyper-V.
            $result = backupHyperVConfig;
            if ($result.SyncRoot)
            {
                $err = $result.SyncRoot[$result.length - 1];
            } else
            {
                $err = $result;
            }
            if ($err -ne $ERROR_SUCCESS)
            {
                $errorStatus = $err;
            }
            $XmlWriter.Save($filePath);
        }
        
        Write-Host "Finished Backing up the configuration with status:" ;
        printError $errorStatus;
        "Finished Backing up the configuration with status=$errorStatus." >> $logFile;
        "#########################################################################" >> $logFile;
        exit $errorStatus;
    }
    # Restore the configuration.
    {($_ -eq "r") -or ($_ -eq "restore")} {
        Write-Host "The log file will be saved in $selectedPath."
        removeFile $defaultsPath;
        "#########################################################################" >> $logFile;
        "Start restoring the configuration." >> $logFile;
        
        # Check if the restart tool exists.
        #$scriptPath_t = Split-Path $script:MyInvocation.MyCommand.Path
        $restExePath_t = Join-Path $restartAppPath "RestartDriver.exe"
        if (!(Test-Path $restExePath_t))
        {
            Write-Host "Error - Restart application in the path $restExePath_t is missing."
            "Error - Restart application is missing." >> $logFile
            exit $ERROR_FILE_MISSING;
        }

        $defaultsWriter = New-Object System.Xml.XmlDocument;
        $root = $defaultsWriter.CreateElement("RootElement");
        $defaultsWriter.AppendChild($root);
        $errorStatus = $ERROR_SUCCESS;
        
        # Save the default values of the registry keys defined as non-overwrite in INF file.
        If (Test-Path $ethINFFileDirectory)
        {
            getDefaultValuesInINF $ethINFFileDirectory $DEFAULT_HEADER_ETH;
        } else 
        {
            Write-Host "ERROR - ETH INF file is missing. $ethINFFileDirectory";
            "ERROR - ETH INF file is missing." >> $logFile;
            exit $ERROR_FILE_MISSING;
        }
        If (Test-Path $ibINFFileDirectory)
        {
            getDefaultValuesInINF $ibINFFileDirectory $DEFAULT_HEADER_IB;
        } else 
        {
            Write-Host "ERROR - IPoIB INF file is missing.";
            "ERROR - IPoIB INF file is missing." >> $logFile;
            exit $ERROR_FILE_MISSING;
        }
        $defaultsWriter.Save($defaultsPath);
        
        try
        {
            $cards = @(Get-WmiObject Win32_PNPEntity -ErrorAction Stop | Where {$_.PNPDeviceID -Match $MLNX_VEN_ID});
        } catch
        {
            $ErrorMessage = "ERROR - Function Get-MlnxPCIDeviceSetting failed with error: " + $_.Exception.Message;
            Write-Host $ErrorMessage;
            $ErrorMessage >> $logFile;
            exit $ERROR_EXCEPTION;
        }
        if ($cards.length -eq 0)
        {
            Write-Host "ERROR - No Mellanox Cards";
            "ERROR - No Mellanox Cards!" >> $logFile;
            exit $ERROR_NO_CARDS;
        }
        If (!(Test-Path $filePath))
        {
            Write-Host "ERROR - Backup file is missing.";
            "ERROR - Backup file is missing." >> $logFile;
            exit $ERROR_FILE_MISSING;
        }
        
        renameInterfaces 0;
        [xml]$backupFile = Get-Content $filePath;
        
        # Set the configuration of the NICs.
        $backupCards = $backupFile.SelectNodes($nicsPathInBackup);
        foreach ($card in $backupCards)
        {
            waitForCardLoad $card
        }
        foreach ($card in $backupCards)
        {
            "Start restoring the configuration for card with location information = " + $card.LocationInfo >> $logFile;
            $cardFound = 0;
            for ($j = 0; $j -lt $cards.length; $j++)
            {
                $deviceID = $cards[$j].PNPDeviceID;
                $deviceProperty = @(Get-ItemProperty -Path $pciPath\$deviceID);
                $locationInfo_t = $deviceProperty.LocationInformation -split "\(";
                $locationInfo = $locationInfo_t[1];
                $locationInfo = $locationInfo -replace "\(", "";
                $locationInfo = $locationInfo -replace "\)", "";
                $locationInfo = $locationInfo -split ",";
                $locationInfo = "PCI bus " + $locationInfo[0] + ", " + "device " + $locationInfo[1] + ", " + "function " + $locationInfo[2];
                if ($card.LocationInfo -eq $locationInfo) {
                    $driverId = $deviceProperty.Driver;
                    #$cardName = $cards[$j].Name;
                    $neededCardIndex = $j;
                    $cardFound = 1;
                    break
                }
            }
            if ($cardFound -eq 0)
            {
                "ERROR - Card with location information = " + $card.LocationInfo + "is missing" >> $logFile;
                $errorStatus = $ERROR_CARD_MISSING;
            } else
            {
                if ($BackupRoceMode -eq 1)
                {
                    if ($card.EnableRoce)
                    {
                        try
                        {
                            Set-ItemProperty -Path $interfacesClass\$driverId\"Parameters" -Name EnableRoce -Value $card.EnableRoce -Type String -ErrorAction Stop;
                        } catch
                        {
                            "ERROR - Failed to set Enable Roce value" >> $logFile;
                            $errorStatus = $ERROR_SET_REG_KEY;
                        }
                    }
                    if ($card.EnableRRoce)
                    {
                        try
                        {
                            Set-ItemProperty -Path $interfacesClass\$driverId\"Parameters" -Name EnableRRoce -Value $card.EnableRRoce -Type String -ErrorAction Stop;
                        } catch
                        {
                            "ERROR - Failed to set Enable RRoce value" >> $logFile;
                            $errorStatus = $ERROR_SET_REG_KEY;
                        }
                    }

                    # Restore the new roce mode.
                    if (!(Test-Path $interfacesClass\$driverId\"Parameters\Roce"))
                    {
                        New-Item -Path $interfacesClass\$driverId\"Parameters" -Name Roce;
                    }
                    try
                    {
                        $newRoceMode = getRoceModeByOldParam $card;
                        Set-ItemProperty -Path $interfacesClass\$driverId\"Parameters\Roce" -Name roce_mode -Value $newRoceMode -Type DWORD -ErrorAction Stop;
                    } catch
                    {
                        "ERROR - Failed to set Roce value" >> $logFile;
                        $errorStatus = $ERROR_SET_REG_KEY;
                    }
                }

                # We add the card to thedefaults file, this will help us to get the name of each card 
                # when we want to restart them or set their ports type.
                addCardToFile $card.LocationInfo $defaultsPath $driverId $deviceID;
    
                # Set the configuration of the interfaces.
                for ($i = 0; $i -lt $INTERFACES_TYPES.length; $i++)
                {
                    $result = setInterafceConfiguration $card $INTERFACES_TYPES[$i] $backupFile $deviceID;
                    if ($result.SyncRoot)
                    {
                        $err = $result.SyncRoot[$result.length - 1];
                    } else
                    {
                        $err = $result;
                    }
                    if ($err -ne $ERROR_SUCCESS)
                    {
                        $errorStatus = $err;
                    }
                }
                
                if ($card.PortType)
                {
                    try
                    {
                        Set-ItemProperty -Path $interfacesClass\$driverId\"Parameters" -Name PortType -Value $card.PortType -Type String -ErrorAction Stop;
                    } catch
                    {
                        "ERROR - Failed to set ports type." >> $logFile;
                        $errorStatus = $ERROR_SET_REG_KEY;
                    }
                }
                
            }
            "Finished restoring the configuration for card with location inforamtion = " + $card.LocationInfo >> $logFile;
        }
        
        # Restore the driver roce mode.
        If ($BackupRoceMode -eq 1)
        {
            if (!(Test-Path $roceModePath))
            {
                 New-Item -Path $mlx4BusParametersPath -Name Roce;
            }
            $roce = $backupFile.SelectNodes($RocePathInBackup);
            $driverRoceMode = getDriverRoceMode $backupCards $roce; 
            try
            {
                 Set-ItemProperty -Path $roceModePath -Name roce_mode -Value $driverRoceMode -Type DWORD -ErrorAction Stop;
            } catch
            {
                "ERROR - Failed to set Roce value" >> $logFile;
                $errorStatus = $ERROR_SET_REG_KEY;
            }
        }
        
        # Restore ND-Providers.
        $ndProviders = $backupFile.SelectNodes($NDProvidersPathInBackup);
        restoreNDProviders $ndProviders;
        
        #restore performance tuning configuration.
        $backupTuningCinfig = $backupFile.SelectNodes($performancePathInBackup);
        restorePerformanceTuning $backupTuningCinfig;
        
        if ($SupportHVT -eq 1)
        {    
            # Restore the teams.
            $backupTeams = $backupFile.SelectNodes($teamsPathInBackup);
            $result = restoreTeams $backupTeams;
            if ($result.SyncRoot)
            {
                $err = $result.SyncRoot[$result.length - 1];
            } else
            {
                $err = $result;
            }
            if ($err -ne $ERROR_SUCCESS)
            {
                $errorStatus = $err;
            }
            
            # Restore Hyper-V Configuration.
            $vSwitches = $backupFile.SelectNodes($HyperVPathInBackup);
            $result = restoreHyperVConfig $vSwitches;
            if ($result.SyncRoot)
            {
                $err = $result.SyncRoot[$result.length - 1];
            } else
            {
                $err = $result;
            }
            if ($err -ne $ERROR_SUCCESS)
            {
                $errorStatus = $err;
            }
        }
                
        # Restore the configuration of the ports and restart the bus driver.
        restartCards $cards $backupCards;
        
        Write-Host "Finished restoring the configuration with status:";
        printError $errorStatus;
        "Finished restoring the configuration with status=$errorStatus." >> $logFile;
        "#########################################################################" >> $logFile;
        
        # Remove the files we created.
        if ($EraseFiles -eq 1)
        {
            Remove-Item -Path $defaultsPath;    
            Remove-Item -Path $filePath;
            Remove-Item -Path $logFile;
        }
        remove-ItemProperty -path HKLM:\Software\Mellanox -name InboxWin2k12Upgrade -ErrorAction SilentlyContinue;
        exit $errorStatus;
    }
    {($_ -eq "h") -or ($_ -eq "help")} { 
        printUsage;
        return $ERROR_SUCCESS;
    }
    {($_ -eq "rb") -or ($_ -eq "rollback")} {
        renameInterfaces 1;
        return $ERROR_SUCCESS;
    }
    default {
        Write-Host "ERROR - Bad input, see usage.";
        "ERROR - Bad input, see usage." >> $logFile;
        printUsage;
        exit $ERROR_BAD_INPUT;
    }    
}

# SIG # Begin signature block
# MIIlUQYJKoZIhvcNAQcCoIIlQjCCJT4CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDAcG/z1bA9iyEc
# BrR2sBUFMItECepShRXjNuQx9e3mZKCCFCowggTQMIIEOaADAgECAhAlDOjgMGEu
# nyuJ9wVNfPj9MA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQK
# Ew5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
# eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMDgwMDAwMDBaFw0yMTEx
# MDcyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIElu
# Yy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShj
# KSAyMDA2IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkx
# RTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlm
# aWNhdGlvbiBBdXRob3JpdHkgLSBHNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
# AQoCggEBAK8kCAgpejWeYAyq50s7Ttx8vDxFHLsr4P4pAvlXCKNkhRUn9fGtyDGJ
# XSLoKqqmQrOP+LlVt7G3S7P+j34HV+zvQ9tmYhVhz2ANpNje+ODDYgg9VBPrScpZ
# VIUm5SuPG5/r9aGRwjNJ2ENjalJL0o/ocFFN0Ylpe8dw9rPcEnTbe11LVtOWvxV3
# obD0oiXyrxySZxjl9AYE75C55ADk3Tq1Gf8CuvQ87uCL6zeL7PTXrPL28D2v3XWR
# MxkdHEDLdCQZIZPZFP6sKlLHj9UESeSNY0eIPGmDy/5HvSt+T8WVrg6d1NFDwGdz
# 4xQIfuU/n3O4MwrPXT80h5aK7lPoJRUCAwEAAaOCAZswggGXMA8GA1UdEwEB/wQF
# MAMBAf8wMQYDVR0fBCowKDAmoCSgIoYgaHR0cDovL2NybC52ZXJpc2lnbi5jb20v
# cGNhMy5jcmwwDgYDVR0PAQH/BAQDAgEGMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgG
# CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vY3BzMB0GA1UdDgQW
# BBR/02Wnwt3su/AwCfNDOfoCrzMxMzBtBggrBgEFBQcBDARhMF+hXaBbMFkwVzBV
# FglpbWFnZS9naWYwITAfMAcGBSsOAwIaBBSP5dMahqyNjmvDz4Bq1EgYLHsZLjAl
# FiNodHRwOi8vbG9nby52ZXJpc2lnbi5jb20vdnNsb2dvLmdpZjA0BggrBgEFBQcB
# AQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnZlcmlzaWduLmNvbTA+BgNV
# HSUENzA1BggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBglghkgBhvhCBAEG
# CmCGSAGG+EUBCAEwDQYJKoZIhvcNAQEFBQADgYEAEwLd+OiGAPJa+PggDFmIYgfO
# zvdO+btZoZjl4TjdTrxmGNOt6xjyDcltPkqUIMM8ur1lVMavRLMQrSxrPqvXB7a4
# gWPF+V4u5Spnzs0zDCrXiVYDIx+zvug6CFm07EU194pb/2bPUK/GbVeNGXi3uaLR
# V+ofmkuvusmOEn7Gvf8wggTuMIID1qADAgECAhA8cikel5PK5eFaY8ev8iXqMA0G
# CSqGSIb3DQEBCwUAMH8xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBD
# b3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEwMC4G
# A1UEAxMnU3ltYW50ZWMgQ2xhc3MgMyBTSEEyNTYgQ29kZSBTaWduaW5nIENBMB4X
# DTE2MDIxNjAwMDAwMFoXDTE4MDQxNjIzNTk1OVowgYUxCzAJBgNVBAYTAklMMRYw
# FAYDVQQIEw1VcHBlciBZb2tuZWFtMRYwFAYDVQQHEw1VcHBlciBZb2tuZWFtMSIw
# IAYDVQQKFBlNZWxsYW5veCBUZWNobm9sb2dpZXMsTFREMSIwIAYDVQQDFBlNZWxs
# YW5veCBUZWNobm9sb2dpZXMsTFREMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
# CgKCAQEA0ef35l3UafBvY5oTxQ0cn5J6zft2VGrdizQY1XQa0PYdaRRyiTGiHvf+
# /33ql6tZq9iUIbUhF6k5isEAV6HA8lZxGz5wJW4PmTxImJ0galL4N+C2Xdi6lpyC
# M778Wh6fEBZz8Fh4csKDlpa+9uSA5y2q97gPioEMRhfSgU3QsmczvLnWXtprEfvf
# Hbrg0oRz2p2tl8TZDfioJzfW0TNZEguHpwpadGdz3bc2pNKOM0UjtnN0CtdsvcPm
# j1rilOOoBKKW0PBppb1YXXgyvMzhsJI3fjwz6C8eDupRcQADUN3BbzbwjTV4gshc
# QnvZ/DzwSKqwsz872WVHQyQjYBJohwIDAQABo4IBXTCCAVkwCQYDVR0TBAIwADAO
# BgNVHQ8BAf8EBAMCB4AwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3N2LnN5bWNi
# LmNvbS9zdi5jcmwwYQYDVR0gBFowWDBWBgZngQwBBAEwTDAjBggrBgEFBQcCARYX
# aHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGQwXaHR0cHM6Ly9k
# LnN5bWNiLmNvbS9ycGEwEwYDVR0lBAwwCgYIKwYBBQUHAwMwVwYIKwYBBQUHAQEE
# SzBJMB8GCCsGAQUFBzABhhNodHRwOi8vc3Yuc3ltY2QuY29tMCYGCCsGAQUFBzAC
# hhpodHRwOi8vc3Yuc3ltY2IuY29tL3N2LmNydDAfBgNVHSMEGDAWgBSWO1PweTOX
# r32D7y4rzMq3hh5yZjAdBgNVHQ4EFgQUB08IS07LhEvBhxbK3WdFCHesFGYwDQYJ
# KoZIhvcNAQELBQADggEBAI5Jb/4sD/yxtoyMf1or8LtahMWXbaQ7nOYagAiF1nGc
# 2NoeDSdeAeFXW1cJ4lFrHtJqmV94XzdmNVe3LANyjcHClNYKMpiGHHz6F7yOuU4y
# PO/hM21n1pGcbZ0B71Ytur8P0o3GIKUaB5CbT7u+4+ZzPWz/4l1d+dTc7JE4s7j3
# RCcIYK1FdH5eChphwQjJcmumJkGeD4YXF33yOwff/V0D8GZ5j9/hpoKOVbL9T7Fu
# MmooqfNcz2jS67zlj77Pwqcab/vGpftJ7yY4KE6KIDDhygcFu5qiiKJ1EzssgU8V
# FuFOWs+ag+Rj2MJ+Oo5KRBv/VyYf+Jjp24IJKxG6Os0wggUDMIIC66ADAgECAgph
# DBIGAAAAAAAbMA0GCSqGSIb3DQEBBQUAMH8xCzAJBgNVBAYTAlVTMRMwEQYDVQQI
# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xKTAnBgNVBAMTIE1pY3Jvc29mdCBDb2RlIFZlcmlmaWNh
# dGlvbiBSb290MB4XDTA2MDUyMzE3MDEyOVoXDTE2MDUyMzE3MTEyOVowXzELMAkG
# A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
# cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0G
# CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL
# 0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnv
# T0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFk
# TGUugWhFpwIDAQABo4IBIzCCAR8wEQYDVR0gBAowCDAGBgRVHSAAMDYGCSsGAQQB
# gjcVBwQpMCcGHysGAQQBgjcVCI3g0YlOhNecwweGpob7HI/Tv6YVARkCAW4CAQAw
# CwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOJ/e9h31d+e
# Cj+etMsOLqnv22l3MB0GCSsGAQQBgjcUAgQQHg4AQwByAG8AcwBzAEMAQTAfBgNV
# HSMEGDAWgBRi+wohW39DbhHaCVRQa/XSlnHxnjBVBgNVHR8ETjBMMEqgSKBGhkRo
# dHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNyb3Nv
# ZnRDb2RlVmVyaWZSb290LmNybDANBgkqhkiG9w0BAQUFAAOCAgEAAeRGsztFf3UT
# h35fQ95GjsuKvbZHQbzMzHSR2M45UZWkprVHwO/S2nuPVxH0Mox8zT/uQtoEIUr3
# yEOISm9cyhT8S9GfTL3UVW7MAr4NpoiPhgm6pCW96LDw+otxTmewy4Ko145V9zfr
# 8D6I7+Tgiv0cbi5hQUh1tLAsHSjYSQ/XFfAkcyU8zIgM3ihMZVT+Xq6M6hmtLFGy
# mzpH9TyANQEX4kmH1lRK+0urB7y/fXnPvzUAXLuez/yCiRs5oFGXtt7Aswf/RJZE
# wDQqGVyr7vA77ClOtRPFN4V+ddW01g0GbrXSbCNxZ+rxcY6vTnSqDPnsv0xY+l6Q
# m205y4aIP4scqBYy1f5tufH4s+rXkfY2R3jAJyoVx2jW9MX8T07IZz8QLUCf8R7J
# YUjnpwP8MXMM8EaI/lbaSSmV7wnao+W+72Ds2VSgWZwovVTvZhV/h0yE26YOlWcu
# UXs0ObZBwoyEaCbcJAIJ54GOCpct7+6nuZimD4GNxxC14e2YL0hvU4VJZHib7F2s
# lwtVJsPvuo3I0aUvWn+Ta2EaM5sYuKJiEN4k6nbhL0Pr7N18EjQkidooVa7ldU4x
# K2djtqjXq3MKA87F6lk/x+sqRa6oYlsvAJk5q7Rfc8MI7IARj0cOjyoTQ+GRBmJV
# u/+6PampPSYPrsp9YosVVYnWlDRN1mUwggVZMIIEQaADAgECAhA9eNf5dklgsmF9
# 9PAeyoYqMA0GCSqGSIb3DQEBCwUAMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMO
# VmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsx
# OjA4BgNVBAsTMShjKSAyMDA2IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6
# ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFBy
# aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHNTAeFw0xMzEyMTAwMDAw
# MDBaFw0yMzEyMDkyMzU5NTlaMH8xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1h
# bnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29y
# azEwMC4GA1UEAxMnU3ltYW50ZWMgQ2xhc3MgMyBTSEEyNTYgQ29kZSBTaWduaW5n
# IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl4MeABavLLHSCMTX
# aJNRYB5x9uJHtNtYTSNiarS/WhtR96MNGHdou9g2qy8hUNqe8+dfJ04LwpfICXCT
# qdpcDU6kDZGgtOwUzpFyVC7Oo9tE6VIbP0E8ykrkqsDoOatTzCHQzM9/m+bCzFhq
# ghXuPTbPHMWXBySO8Xu+MS09bty1mUKfS2GVXxxw7hd924vlYYl4x2gbrxF4Gpiu
# xFVHU9mzMtahDkZAxZeSitFTp5lbhTVX0+qTYmEgCscwdyQRTWKDtrp7aIIx7mXK
# 3/nVjbI13Iwrb2pyXGCEnPIMlF7AVlIASMzT+KV93i/XE+Q4qITVRrgThsIbnepa
# ON2b2wIDAQABo4IBgzCCAX8wLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUFBzABhhNo
# dHRwOi8vczIuc3ltY2IuY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwbAYDVR0gBGUw
# YzBhBgtghkgBhvhFAQcXAzBSMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LnN5bWF1
# dGguY29tL2NwczAoBggrBgEFBQcCAjAcGhpodHRwOi8vd3d3LnN5bWF1dGguY29t
# L3JwYTAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vczEuc3ltY2IuY29tL3BjYTMt
# ZzUuY3JsMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDAzAOBgNVHQ8BAf8E
# BAMCAQYwKQYDVR0RBCIwIKQeMBwxGjAYBgNVBAMTEVN5bWFudGVjUEtJLTEtNTY3
# MB0GA1UdDgQWBBSWO1PweTOXr32D7y4rzMq3hh5yZjAfBgNVHSMEGDAWgBR/02Wn
# wt3su/AwCfNDOfoCrzMxMzANBgkqhkiG9w0BAQsFAAOCAQEAE4UaHmmpN/egvaSv
# fh1hU/6djF4MpnUeeBcj3f3sGgNVOftxlcdlWqeOMNJEWmHbcG/aIQXCLnO6SfHR
# k/5dyc1eA+CJnj90Htf3OIup1s+7NS8zWKiSVtHITTuC5nmEFvwosLFH8x2iPu6H
# 2aZ/pFalP62ELinefLyoqqM9BAHqupOiDlAiKRdMh+Q6EV/WpCWJmwVrL7TJAUwn
# ewusGQUioGAVP9rJ+01Mj/tyZ3f9J5THujUOiEn+jf0or0oSvQ2zlwXeRAwV+jYr
# A9zBUAHxoRFdFOXivSdLVL4rhF4PpsN0BQrvl8OJIrEfd/O9zUPU8UypP7WLhK9k
# 8tAUITGCEH0wghB5AgEBMIGTMH8xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1h
# bnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29y
# azEwMC4GA1UEAxMnU3ltYW50ZWMgQ2xhc3MgMyBTSEEyNTYgQ29kZSBTaWduaW5n
# IENBAhA8cikel5PK5eFaY8ev8iXqMA0GCWCGSAFlAwQCAQUAoHwwEAYKKwYBBAGC
# NwIBDDECMAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB
# CzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIDdEctECh+0mfpTwn2eq
# UrDu8SczL2UlrkdP/mvCWVMmMA0GCSqGSIb3DQEBAQUABIIBABJYgNHpKQLdUrp6
# N99MOphMswB/7oo99HzuZDE96kk7KzdDCwXwdfg32A6HP+7HSyNorP/Nf8VrR1Kw
# AwwP4TygyQxW/kVjBFkgIXScv2D4goj5GdUi6FwU1Vmi6uACwc6dkcs7xjqlTf4R
# bC/CFbbYExFThpMjBScAPKG0HPZ0PYxuvCGJWMBa7fy8rxDrTcAFuSZkm7L9JDux
# +to5ybQdiqtRkAkfVipTphapo6qC4tRulvXrBM29YMIrwJDHhZeYc7BAHfY4OY6P
# 7qq/pjwemWmOkZpUIeJAGV5D67oUB4n9MySrLHXYMhtXSgMdW3WkjZ8bgqJRm3b7
# A3dPcGuhgg48MIIOOAYKKwYBBAGCNwMDATGCDigwgg4kBgkqhkiG9w0BBwKggg4V
# MIIOEQIBAzENMAsGCWCGSAFlAwQCATCCAQ4GCyqGSIb3DQEJEAEEoIH+BIH7MIH4
# AgEBBgtghkgBhvhFAQcXAzAxMA0GCWCGSAFlAwQCAQUABCA+2hygG6aULzq161Lr
# YvQ00cT2rhtLnYfxSMV4Umd6SgIUBoWloMD8W7GxT3M6hJGFyjRtZtsYDzIwMTYw
# ODI4MTI0OTE0WjADAgEeoIGGpIGDMIGAMQswCQYDVQQGEwJVUzEdMBsGA1UEChMU
# U3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5l
# dHdvcmsxMTAvBgNVBAMTKFN5bWFudGVjIFNIQTI1NiBUaW1lU3RhbXBpbmcgU2ln
# bmVyIC0gRzGgggqLMIIFODCCBCCgAwIBAgIQewWx1EloUUT3yYnSnBmdEjANBgkq
# hkiG9w0BAQsFADCBvTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJ
# bmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEo
# YykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
# MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u
# IEF1dGhvcml0eTAeFw0xNjAxMTIwMDAwMDBaFw0zMTAxMTEyMzU5NTlaMHcxCzAJ
# BgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UE
# CxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEoMCYGA1UEAxMfU3ltYW50ZWMgU0hB
# MjU2IFRpbWVTdGFtcGluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
# ggEBALtZnVlVT52Mcl0agaLrVfOwAa08cawyjwVrhponADKXak3JZBRLKbvC2Sm5
# Luxjs+HPPwtWkPhiG37rpgfi3n9ebUA41JEG50F8eRzLy60bv9iVkfPw7mz4rZY5
# Ln/BJ7h4OcWEpe3tr4eOzo3HberSmLU6Hx45ncP0mqj0hOHE0XxxxgYptD/kgw0m
# w3sIPk35CrczSf/KO9T1sptL4YiZGvXA6TMU1t/HgNuR7v68kldyd/TNqMz+CfWT
# N76ViGrF3PSxS9TO6AmRX7WEeTWKeKwZMo8jwTJBG1kOqT6xzPnWK++32OTVHW0R
# OpL2k8mc40juu1MO1DaXhnjFoTcCAwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIB
# BjASBgNVHRMBAf8ECDAGAQH/AgEAMGYGA1UdIARfMF0wWwYLYIZIAYb4RQEHFwMw
# TDAjBggrBgEFBQcCARYXaHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUH
# AgIwGRoXaHR0cHM6Ly9kLnN5bWNiLmNvbS9ycGEwLgYIKwYBBQUHAQEEIjAgMB4G
# CCsGAQUFBzABhhJodHRwOi8vcy5zeW1jZC5jb20wNgYDVR0fBC8wLTAroCmgJ4Yl
# aHR0cDovL3Muc3ltY2IuY29tL3VuaXZlcnNhbC1yb290LmNybDATBgNVHSUEDDAK
# BggrBgEFBQcDCDAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIw
# NDgtMzAdBgNVHQ4EFgQUr2PWyqNOhXLgp7xB8ymiOH+AdWIwHwYDVR0jBBgwFoAU
# tnf6aUhHn1MS1cLqBzJ2B9GXBxkwDQYJKoZIhvcNAQELBQADggEBAHXqsC3VNBlc
# MkX+DuHUT6Z4wW/X6t3cT/OhyIGI96ePFeZAKa3mXfSi2VZkhHEwKt0eYRdmIFYG
# mBmNXXHy+Je8Cf0ckUfJ4uiNA/vMkC/WCmxOM+zWtJPITJBjSDlAIcTd1m6JmDy1
# mJfoqQa3CcmPU1dBkC/hHk1O3MoQeGxCbvC2xfhhXFL1TvZrjfdKer7zzf0D19n2
# A6gP41P3CnXsxnUuqmaFBJm3+AZX4cYO9uiv2uybGB+queM6AL/OipTLAduexzi7
# D1Kr0eOUA2AKTaD+J20UMvw/l0Dhv5mJ2+Q5FL3a5NPD6itas5VYVQR9x5rsIwON
# hSrS/66pYYEwggVLMIIEM6ADAgECAhBU832hcWdRvGqNCtJ0sosTMA0GCSqGSIb3
# DQEBCwUAMHcxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3Jh
# dGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEoMCYGA1UEAxMf
# U3ltYW50ZWMgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTAeFw0xNjAxMTIwMDAwMDBa
# Fw0yNzA0MTEyMzU5NTlaMIGAMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50
# ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsx
# MTAvBgNVBAMTKFN5bWFudGVjIFNIQTI1NiBUaW1lU3RhbXBpbmcgU2lnbmVyIC0g
# RzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCf+9+PH6fPnj4ay+to
# rc8nHO6BVamHCFjlgU0JFODt0PPUDz8hth4ONNTxaApvfY+J2fLqp9glOKSMNsru
# KM8z+HU92J3Pkt1W4/aweVRmtUWCQ0TSarGrF6LD5e8A6ifzJ4gOhzz2bryp7Pa7
# Lmp3BiK9+rh/wyQH9z+7TLD/Q8uTyhKqlSQAkLIrNqLS3dKz0Zky3c/0zHMWSYN/
# JOvteEbT7l9sQmUbZ43wJhoOXoduWo+ggn5un80m3r1h70ReRYuolNMcBDKh/6Sn
# oqp3Adsq3g9MkjbGaaxchICtJfXtMMNoHRfbCk2aNHhZAZtrAoU44idxohRUMGCT
# IEgjAgMBAAGjggHHMIIBwzAMBgNVHRMBAf8EAjAAMGYGA1UdIARfMF0wWwYLYIZI
# AYb4RQEHFwMwTDAjBggrBgEFBQcCARYXaHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMw
# JQYIKwYBBQUHAgIwGRoXaHR0cHM6Ly9kLnN5bWNiLmNvbS9ycGEwQAYDVR0fBDkw
# NzA1oDOgMYYvaHR0cDovL3RzLWNybC53cy5zeW1hbnRlYy5jb20vc2hhMjU2LXRz
# cy1jYS5jcmwwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQDAgeA
# MHcGCCsGAQUFBwEBBGswaTAqBggrBgEFBQcwAYYeaHR0cDovL3RzLW9jc3Aud3Mu
# c3ltYW50ZWMuY29tMDsGCCsGAQUFBzAChi9odHRwOi8vdHMtYWlhLndzLnN5bWFu
# dGVjLmNvbS9zaGEyNTYtdHNzLWNhLmNlcjAoBgNVHREEITAfpB0wGzEZMBcGA1UE
# AxMQVGltZVN0YW1wLTIwNDgtNDAdBgNVHQ4EFgQU7WtgzztY+D4yzL+k6Kvo6qJQ
# Qn8wHwYDVR0jBBgwFoAUr2PWyqNOhXLgp7xB8ymiOH+AdWIwDQYJKoZIhvcNAQEL
# BQADggEBAKKNXl0d7k7Sk/1P5fRtpvCJRVW7CMqrJKEWJMlPF8Gf9N0CmsJHwKnc
# iIl3wYaG8dVJlvP7HpjWyR01I4iZimLhdahNeKc97CSAFZ5o1DqkwkzccWyWnY4e
# DC5sUgGeVpA/ol6SzbbaQRokg6F6o1/+jTtvOdE/QV9WHCcM5XwF2Gc2iOWwwsME
# o1pWuBIEjtScJGsbZrS+oBrhtc3s40SksTznkvNY3d/osVhLcEvOkADM3KPR0m51
# FlREAu8bVERj6LVwyLlHmltFxG52mhix9xAzyAtR9VWM/SEeQY9OPpBdgAHIvCR+
# hmgUFRQ0NXRJt4dSKdaWXqKjFtSw03sxggJaMIICVgIBATCBizB3MQswCQYDVQQG
# EwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5
# bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVjIFNIQTI1NiBU
# aW1lU3RhbXBpbmcgQ0ECEFTzfaFxZ1G8ao0K0nSyixMwCwYJYIZIAWUDBAIBoIGk
# MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMTYw
# ODI4MTI0OTE0WjAvBgkqhkiG9w0BCQQxIgQg3j1x3UwH2pxwFFmJnzklz8+HPwOW
# rmvIbgdhVkVkHBgwNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQggtVW29tdrV+ge7YH
# JqbYbnMLW7cpiFu23k/ydSkCLPwwCwYJKoZIhvcNAQEBBIIBAAOF1gEu8XDZBJl7
# +qq0U4r905eqCao0ym3k210gqr5EB3uUuu+Koqvfvj2YiNvICb8vIqaZVmrPeNfU
# rVNnUzoua4daIDwzuyGv1/R0h3wHts09w8xKckDqVlCEhYyTRidzRkPbl7bww3Sp
# AOy+c9TTO+m1HP5ESXAD9JMzUtNwiY5NFAIghDD6wLyFS0C5OzflDkbfgDo083cD
# o/0SM7qQwi6e54+IzcqTAfdlBLx4tXdO2wQo3wMRDIoGYYeV8GyU2zBulbYsZ9Ni
# a22EnoHFRvGg+nSsYMSe38jno2B6nvJO05/AAh7S9/xhzjloZRM0IrpeTw3W5H7Y
# gVnMRuA=
# SIG # End signature block
