(C) Ondrej Sevecek, 2019 - www.sevecek.com, ondrej@sevecek.com
$libDir = Split-Path -parent $MyInvocation.MyCommand.Definition & "$libDir\lib-common.ps1" -defaultConfig -rootDir $libDir -outFile nlbLib & "$libDir\lib-modifyActions.ps1" & "$libDir\lib-buildup.ps1" $vmName = $args[0] DBG ('NLB installation library') Redirect-TempToOutput Load-VMConfig Find-MarkedVolumes $appTag = 'nlb' $appConfig = $vmConfig.$appTag $firstAppHost = Get-FirstAppHostInInstance $appTag $appConfig.instance 'waitParams' $firstAppConfig = (Get-FirstAppHostInInstance $appTag $appConfig.instance 'vmConfig').$appTag $firstAppHostInInstance = Check-FirstAppHostInInstance $appTag $appConfig.instance $firstAppHostFQDN = Get-FirstAppHostInInstance $appTag $appConfig.instance 'fqdn' if (-not $firstAppHostInInstance) { $allPreviousAppHosts = Get-AllAppHostsOfInstance $appTag $appConfig.instance 'waitParams' -onlyBeforeMyHostName $vmConfig.hostName } if (Is-Null $appConfig) { DBG ('Invalid appCofnig, exiting'); exit } #==================== #==================== ################ # # Note: Main code # if ($global:thisOSVersionNumber -lt 6.1) { DBGIF $MyInvocation.MyCommand.Name { $global:thisOSVersionNumber -lt 6.3 } exit } # # Note: on Windows Server 2016 the IPv6 must be completelly enabled in order to configure the new NLB cluster # or we get "Provider load failure" errors or error 314 [string] $sevecekDisabledComponentsBackupValue = 'SevecekDisabledComponentsBackup' DBGSTART [long] $regIPv6DisablerReal = (Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\TCPIP6\Parameters).DisabledComponents [long] $regIPv6DisablerBackup = (Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\TCPIP6\Parameters).$sevecekDisabledComponentsBackupValue DBGEND DBG ('IPv6 disabling registry DisabledComponents values: value = {0} | backup = {1}' -f $regIPv6DisablerReal, $regIPv6DisablerBackup) if (($global:thisOSVersionNumber -ge 10) -and ($regIPv6DisablerReal -ne 0)) { DBG ('Creating DisabledComponents backup and resetting the original value') DBGSTART Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\TCPIP6\Parameters -Name DisabledComponents -Value 0 -Type DWord Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\TCPIP6\Parameters -Name $sevecekDisabledComponentsBackupValue -Value $regIPv6DisablerReal -Type DWord DBGER $MyInvocation.MyCommand.Name $error DBGEND DBGIF ('NLB cluster requires IPv6 to configure. Trying again after restart.') { $true } exit $global:VM_RECYCLE_REQUIRED } # # [string] $clusterName = $appConfig.instance [string] $nlbIp = $firstAppConfig.ip [string] $nlbMask = $firstAppConfig.mask [string] $nlbType = $firstAppConfig.type [string] $nlbSubnet = Get-IPSubnet $nlbIp $nlbMask DBG ('Get the best NIC on my computer: {0} | {1}' -f $nlbSubnet, $vmConfig.hostName) # Note: we could have more IPs on a single interface so we must get just a single representation here [object[]] $bestNICs = (Get-NetworkMap $vmConfig.hostName) | ? { ($_.subnetIP -eq $nlbSubnet) -and (Is-EmptyString $_.nlbInstance) } | select -Unique nicName, subnetIP DBGIF $MyInvocation.MyCommand.Name { (Get-CountSafe $bestNICs) -ne 1 } [string] $nicName = $bestNICs[0].nicName DBG ('The best NIC determined: {0}' -f $nicName) # # [bool] $loggingEnabledByScript = $false try { [string] $nlbLogFileName = Get-DataFileApp nlbBuildupLogFile $null '.txt' DBG ('Enable NLB logging for duration of the buildup: {0}' -f $nlbLogFileName) [int] $currentLoggingEnabled = Get-RegValue '.' 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\NLB' LoggingEnabled DWord [string] $currentLogFileName = Get-RegValue '.' 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\NLB' LogFileName String DBGIF $MyInvocation.MyCommand.Name { ($currentLoggingEnabled -ne 0) -or (Is-ValidString $currentLogFileName) } Set-RegistryValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NLB' LogFileName $nlbLogFileName String Set-RegistryValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NLB' LoggingEnabled 1 DWord $loggingEnabledByScript = $true # # DBG ('Import the NLB powershell module') DBGSTART Import-Module NetworkLoadBalancingClusters DBGER $MyInvocation.MyCommand.Name $error DBGEND if ($firstAppHostInInstance) { DBG ('Check first if there is not a partially configured cluster from the previous failed run') DBGSTART $someNlbExists = $null $someNlbExists = Get-NlbCluster -HostName localhost # Note: we must ignore errors because if there is no cluster it would raise some error #DBGER $MyInvocation.MyCommand.Name $error DBGEND if (Is-NonNull $someNlbExists) { DBG ('Must delete existing NLB cluster with possibly incomplete configuration: {0} | {1}' -f $someNlbExists.Name, $someNlbExists.IPAddress) DBGSTART Remove-NlbCluster -HostName localhost -Force DBGER $MyInvocation.MyCommand.Name $error DBGEND } DBG ('Create new NLB cluster: clusterName = {0} | clusterPrimaryIP = {1} | subnetMask = {2} | operationMode = {3} | interfaceName = {4}' -f $clusterName, $nlbIp, $nlbMask, $nlbType, $nicName) DBGSTART $newCluster = $null $newCluster = New-NlbCluster -ClusterName $clusterName -InterfaceName $nicName -OperationMode $nlbType -ClusterPrimaryIP $nlbIp -SubnetMask $nlbMask [bool] $errorOccured = $error.Count -gt 0 DBGER $MyInvocation.MyCommand.Name $error DBGEND if ((Is-Null $newCluster) -or ($errorOccured)) { # Note: on Windows 2016 TP4 and TP5 and RTM this error 314 occurs which results in # partially configured NLB cluster with invalid configuration, so we restart # and remove it. if (Is-Null $someNlbExists) { DBGIF ('NLB cluster was not created successfully. Trying again after restart.') { $true } exit $global:VM_RECYCLE_REQUIRED } else { DBGIF ('This is the second time the NLB cluster promotion failed. Just continue and dont bother, we must not cycle forever') { $true } } } if (Is-NonNull $newCluster) { DBG ('Clear all current port rules') DBGSTART Get-NlbClusterPortRule | Remove-NlbClusterPortRule -Force DBGER $MyInvocation.MyCommand.Name $Error DBGEND DBG ('Add all requested application port rules') $portRules = $xmlConfig.SelectNodes('./VMs/MACHINE[vm/@do="true"]//nlbrule[translate(@instance,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz")="{0}"]' -f $appConfig.instance.ToLower()) DBG ('Port rules requested: {0}' -f (Get-CountSafe $portRules)) if ((Get-CountSafe $portRules) -gt 0) { foreach ($onePortRule in $portRules) { DBG ('Add one port rule: {0} | {1} | {2}' -f $onePortRule.proto, $onePortRule.port, $onePortRule.affinity) DBGSTART Add-NlbClusterPortRule -Protocol $onePortRule.proto -StartPort $onePortRule.port -EndPort $onePortRule.port -InterfaceName $nicName -Mode Multiple -Affinity $onePortRule.affinity DBGER $MyInvocation.MyCommand.Name DBGEND } } } } if (-not $firstAppHostInInstance) { DBG ('Wait for the first NLB node to finish') Wait-MachineAllPrevious $allPreviousAppHosts DBG ('Join existing NLB cluster: {0} | {1} | {2} | {3} | {4}' -f $clusterName, $nlbIp, $nlbMask, $nlbType, $nicName) DBG ('Get the existing cluster from first host: {0}' -f $firstAppHostFQDN) DBGSTART $existingCluster = Get-NlbCluster -HostName $firstAppHostFQDN DBGER $MyInvocation.MyCommand.Name $Error DBGEND DBGIF $MyInvocation.MyCommand.Name { Is-Null $existingCluster } DBGIF ('Weird cluster IP address: {0} | {1}' -f $nlbIp, $existingCluster.IPAddress) { $existingCluster.IPAddress -ne $nlbIp } DBGIF ('Weird cluster name: {0} | {1}' -f $clusterName, $existingCluster.Name) { $existingCluster.Name -ne $clusterName } DBG ('Joining cluster: {0}' -f $existingCluster.Name) DBGSTART Add-NlbClusterNode -Input $existingCluster -NewNodeName localhost -NewNodeInterface $nicName DBGER $MyInvocation.MyCommand.Name $Error DBGEND } } catch { DBGER $MyInvocation.MyCommand.Name $_ } finally { if ($loggingEnabledByScript) { DBG ('Disable NLB logging again after the buildup: {0}' -f $nlbLogFileName) $currentLoggingEnabled = Get-RegValue '.' 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\NLB' LoggingEnabled DWord $currentLogFileName = Get-RegValue '.' 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\NLB' LogFileName String DBGIF $MyInvocation.MyCommand.Name { ($currentLoggingEnabled -ne 1) -or ($currentLogFileName -ne $nlbLogFileName) } DBGSTART Remove-ItemProperty -Literal 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NLB' LogFileName -Force Remove-ItemProperty -Literal 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NLB' LoggingEnabled -Force DBGER $MyInvocation.MyCommand.Name $error DBGEND } } # # if (($global:thisOSVersionNumber -ge 10) -and ($regIPv6DisablerBackup -ne 0)) { DBG ('Restoring DisabledComponents backup') DBGSTART Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\TCPIP6\Parameters -Name DisabledComponents -Value $regIPv6DisablerBackup -Type DWord Remove-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\TCPIP6\Parameters -Name $sevecekDisabledComponentsBackupValue DBGER $MyInvocation.MyCommand.Name $error DBGEND } # # DBG ('Throw up any remaining errors') DBGSTART; DBGEND # SIG # Begin signature block # MIIc2AYJKoZIhvcNAQcCoIIcyTCCHMUCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU4bZs2f8jh/Zzjb+aMWyxunoH # MXigghgEMIIE5TCCA82gAwIBAgIQOb1CntKBbrrVvMkDtLpl5zANBgkqhkiG9w0B # AQsFADB1MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEpMCcG # A1UECxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIzAhBgNVBAMT # GlN0YXJ0Q29tIENsYXNzIDIgT2JqZWN0IENBMB4XDTE2MTIwMTE1NTExM1oXDTE4 # MTIwMTE1NTExM1owUTELMAkGA1UEBhMCQ1oxGjAYBgNVBAgMEUppaG9tb3JhdnNr # eSBLcmFqMQ0wCwYDVQQHDARCcm5vMRcwFQYDVQQDDA5PbmRyZWogU2V2ZWNlazCC # ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK/RPYTY9Om2rIfSV/e5KbKi # vWf3IjgQurayOJ75VvQj8ISgU2+cAK4cS2GQRvY1j1q3ctZy/3JuajKgW/5qIGMD # MLxGFjL7CDjlZ+hw/ZVYTQKLw+jx89M4gQSiLM1048lD0GqCJSBC6L8/eu5u/ByX # VGSRsaoZbgLEvaPf3xMwO111IVLqkSrHrbmVfwLH4ebDr3nqEbG3luHWk1r7c90y # blCy9MONyzVWCZHeiy/HHoLyz1WVHtTe7JL4nRL57XZaMELCZahXax90hiiDygOj # m3GPEmVpBEEm1QRfCrptVE/ozdIJvvOBcDoOVqisflb0ytpY1Vpz6wg9Gc7tqCEC # AwEAAaOCAZMwggGPMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD # AzAJBgNVHRMEAjAAMB0GA1UdDgQWBBRtr0qNzYUFiC3lLNKDfV8x03o3HzAfBgNV # HSMEGDAWgBQ+YpOa18cZ7j6PSRCFVRUg45SEHDBtBggrBgEFBQcBAQRhMF8wJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbTA3BggrBgEFBQcwAoYr # aHR0cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvc2NhLmNvZGUyLmNydDA2BgNV # HR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9zY2EtY29kZTIu # Y3JsMCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzBRBgNVHSAE # SjBIMAgGBmeBDAEEATA8BgsrBgEEAYG1NwECBTAtMCsGCCsGAQUFBwIBFh9odHRw # czovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5MA0GCSqGSIb3DQEBCwUAA4IBAQCb # kYhLx7SGEqbJjJD4U8+EDjkoTd6eSlnX/L5u9QN9wkfX3bNdHfA9gdmhPr45hyev # RmNG234OaGWNi7Ktnri+w2uf4UvPuk9zBLQ+IZ43x1e5sZqEnxbsvyg4qaFersIS # PpLKnIV2HVB/ubgkDtDDjvCE4wIM1ELJ2eFCARwRnj/nvt5Y8UmEl1nTyK4MXUfe # 9T/x4VklXyjZZgYBCjEDOSctGgHeI8UpfwM3WLdPuqZYhSdaXhoXRZ4thZvH7uaD # evGkyKzbXOVmOy84H/rEU1XljkVkt+/tcwA9Jo83fIMnwS8UbmkUn42MZ8tKy13p # QMH4gN83tg1NgX4Pf633MIIF2DCCA8CgAwIBAgIQbDvSft08lJ6Vjiips8dXoDAN # BgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20g # THRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu # ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN # MTUxMjE2MDEwMDA1WhcNMzAxMjE2MDEwMDA1WjB1MQswCQYDVQQGEwJJTDEWMBQG # A1UEChMNU3RhcnRDb20gTHRkLjEpMCcGA1UECxMgU3RhcnRDb20gQ2VydGlmaWNh # dGlvbiBBdXRob3JpdHkxIzAhBgNVBAMTGlN0YXJ0Q29tIENsYXNzIDIgT2JqZWN0 # IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuRQEWPeyxYYsCDJg # rQgmwIF3uWgZ2RUrHRhp5NoalgWXLmR5Gqk9UTNa0Hdq9AKTQcOOunAbq9h7dG+Y # 6Ne5qT5odqSJoCKsF9Yp+Lu4YZ/SB9BmDjBHICtwAh7+cwkccTS14n6prKin8Y46 # QAZ2ksr3eGzvWAVzfX+DUOmiVQLjAK6Wp8bCZHvj+FhAlS5Ne7/dggDeSVWnMyPm # 2k/5YKOTVXExJJaAlYkmyH1OiC3soTkkGb6aJjGJPHiaiNJ4pjkySX5l2p4DQ7K1 # /J6ft5Vw9PuqwmYrF0ViGnn38kzB2d9UI9Q+dFmHUbV+cnr+FoGl6CiUDd5ZIF1H # Mrb8hwIDAQABo4IBWjCCAVYwDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsG # AQUFBwMDMBIGA1UdEwEB/wQIMAYBAf8CAQAwMgYDVR0fBCswKTAnoCWgI4YhaHR0 # cDovL2NybC5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMGYGCCsGAQUFBwEBBFowWDAk # BggrBgEFBQcwAYYYaHR0cDovL29jc3Auc3RhcnRzc2wuY29tMDAGCCsGAQUFBzAC # hiRodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9jYS5jcnQwHQYDVR0OBBYE # FD5ik5rXxxnuPo9JEIVVFSDjlIQcMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0 # aEPQQa7yMD8GA1UdIAQ4MDYwNAYEVR0gADAsMCoGCCsGAQUFBwIBFh5odHRwOi8v # d3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kwDQYJKoZIhvcNAQELBQADggIBAGOlPNWz # bSco2Ou6U68wC+pKXRLV+ZrKcPpMY4zXTVR+RupS54WhJCManab2P1ncPlHTbRMb # PjfHnyj0sIdpvwcV49n0nizMF3MBxaKJEnBBEfHs9Krgjc4qKjR2nOywlzxJ0M27 # RthR5XjyjQ1ofHlOisYgMzcyKyMT7YYpxxoC0wTgAh0DNmE5Q/GKFOaDd3S5gTqr # R9AQzGaC3IxCKBFtcwvk51W98lNRtMbm+oJze5T+dL2wIhyWK58sEIl2paAVfAfW # GH3umYL46scLn8BXDFchN1Jgrg07DqY6gxCqSdubPhVHZInuVagktWmrnS6N9V/v # VLz+OaX4Mkas8n1J1RIR+GV8ZQVmTM49l6L+fpv/h95MWLhQOcXanbIY/2cdNEuz # 5AkhfvDNTQnLxYEMIyMOtW2QIwwZdz92vMTU17G9goxXYjSm09yw+iBniH9G/xGz # 39BV3bwa8ZtKHzDoZ54HT6JT2AraDhrWTwFXv8Xrvv2cir+k0h5bIWlDtImH7Jm1 # 52edb77f5JI8JrPf6jxcUrhNH4xHxe2kGs8ERA39oYlT0dKQIb0obTN6FOF63hBR # FFhGB7NuX2FeFjJsZFCkoJkpsEauObb7Rh+C02+fnHfoi6ivKwUC9BOsWlI4xn7G # Me27niL6k7wpK0L6MTG5/6gxwosqaMA1aukwMIIGajCCBVKgAwIBAgIQAwGaAjr/ # WLFr1tXq5hfwZjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UE # ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD # VQQDExhEaWdpQ2VydCBBc3N1cmVkIElEIENBLTEwHhcNMTQxMDIyMDAwMDAwWhcN # MjQxMDIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNlcnQx # JTAjBgNVBAMTHERpZ2lDZXJ0IFRpbWVzdGFtcCBSZXNwb25kZXIwggEiMA0GCSqG # SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjZF38fLPggjXg4PbGKuZJdTvMbuBTqZ8f # ZFnmfGt/a4ydVfiS457VWmNbAklQ2YPOb2bu3cuF6V+l+dSHdIhEOxnJ5fWRn8YU # Oawk6qhLLJGJzF4o9GS2ULf1ErNzlgpno75hn67z/RJ4dQ6mWxT9RSOOhkRVfRiG # BYxVh3lIRvfKDo2n3k5f4qi2LVkCYYhhchhoubh87ubnNC8xd4EwH7s2AY3vJ+P3 # mvBMMWSN4+v6GYeofs/sjAw2W3rBerh4x8kGLkYQyI3oBGDbvHN0+k7Y/qpA8bLO # cEaD6dpAoVk62RUJV5lWMJPzyWHM0AjMa+xiQpGsAsDvpPCJEY93AgMBAAGjggM1 # MIIDMTAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAK # BggrBgEFBQcDCDCCAb8GA1UdIASCAbYwggGyMIIBoQYJYIZIAYb9bAcBMIIBkjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCCAWQGCCsG # AQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAgAG8AZgAgAHQAaABpAHMAIABD # AGUAcgB0AGkAZgBpAGMAYQB0AGUAIABjAG8AbgBzAHQAaQB0AHUAdABlAHMAIABh # AGMAYwBlAHAAdABhAG4AYwBlACAAbwBmACAAdABoAGUAIABEAGkAZwBpAEMAZQBy # AHQAIABDAFAALwBDAFAAUwAgAGEAbgBkACAAdABoAGUAIABSAGUAbAB5AGkAbgBn # ACAAUABhAHIAdAB5ACAAQQBnAHIAZQBlAG0AZQBuAHQAIAB3AGgAaQBjAGgAIABs # AGkAbQBpAHQAIABsAGkAYQBiAGkAbABpAHQAeQAgAGEAbgBkACAAYQByAGUAIABp # AG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgAGgAZQByAGUAaQBuACAAYgB5ACAAcgBl # AGYAZQByAGUAbgBjAGUALjALBglghkgBhv1sAxUwHwYDVR0jBBgwFoAUFQASKxOY # spkH7R7for5XDStnAs0wHQYDVR0OBBYEFGFaTSS2STKdSip5GoNL9B6Jwcp9MH0G # A1UdHwR2MHQwOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy # dEFzc3VyZWRJRENBLTEuY3JsMDigNqA0hjJodHRwOi8vY3JsNC5kaWdpY2VydC5j # b20vRGlnaUNlcnRBc3N1cmVkSURDQS0xLmNybDB3BggrBgEFBQcBAQRrMGkwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1 # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0Et # MS5jcnQwDQYJKoZIhvcNAQEFBQADggEBAJ0lfhszTbImgVybhs4jIA+Ah+WI//+x # 1GosMe06FxlxF82pG7xaFjkAneNshORaQPveBgGMN/qbsZ0kfv4gpFetW7easGAm # 6mlXIV00Lx9xsIOUGQVrNZAQoHuXx/Y/5+IRQaa9YtnwJz04HShvOlIJ8OxwYtNi # S7Dgc6aSwNOOMdgv420XEwbu5AO2FKvzj0OncZ0h3RTKFV2SQdr5D4HRmXQNJsQO # fxu19aDxxncGKBXp2JPlVRbwuwqrHNtcSCdmyKOLChzlldquxC5ZoGHd2vNtomHp # igtt7BIYvfdVVEADkitrwlHCCkivsNRu4PQUCjob4489yq9qjXvc2EQwggbNMIIF # taADAgECAhAG/fkDlgOt6gAK6z8nu7obMA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNV # BAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp # Y2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAe # Fw0wNjExMTAwMDAwMDBaFw0yMTExMTAwMDAwMDBaMGIxCzAJBgNVBAYTAlVTMRUw # EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x # ITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMTCCASIwDQYJKoZIhvcN # AQEBBQADggEPADCCAQoCggEBAOiCLZn5ysJClaWAc0Bw0p5WVFypxNJBBo/JM/xN # RZFcgZ/tLJz4FlnfnrUkFcKYubR3SdyJxArar8tea+2tsHEx6886QAxGTZPsi3o2 # CAOrDDT+GEmC/sfHMUiAfB6iD5IOUMnGh+s2P9gww/+m9/uizW9zI/6sVgWQ8DIh # FonGcIj5BZd9o8dD3QLoOz3tsUGj7T++25VIxO4es/K8DCuZ0MZdEkKB4YNugnM/ # JksUkK5ZZgrEjb7SzgaurYRvSISbT0C58Uzyr5j79s5AXVz2qPEvr+yJIvJrGGWx # wXOt1/HYzx4KdFxCuGh+t9V3CidWfA9ipD8yFGCV/QcEogkCAwEAAaOCA3owggN2 # MA4GA1UdDwEB/wQEAwIBhjA7BgNVHSUENDAyBggrBgEFBQcDAQYIKwYBBQUHAwIG # CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgwggHSBgNVHSAEggHJMIIBxTCC # AbQGCmCGSAGG/WwAAQQwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3LmRpZ2lj # ZXJ0LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUHAgIwggFW # HoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBm # AGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0 # AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAv # AEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0 # AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAg # AGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBw # AG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBu # AGMAZQAuMAsGCWCGSAGG/WwDFTASBgNVHRMBAf8ECDAGAQH/AgEAMHkGCCsGAQUF # BwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMG # CCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRB # c3N1cmVkSURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3Js # My5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2 # hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290 # Q0EuY3JsMB0GA1UdDgQWBBQVABIrE5iymQftHt+ivlcNK2cCzTAfBgNVHSMEGDAW # gBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEARlA+ybco # JKc4HbZbKa9Sz1LpMUerVlx71Q0LQbPv7HUfdDjyslxhopyVw1Dkgrkj0bo6hnKt # OHisdV0XFzRyR4WUVtHruzaEd8wkpfMEGVWp5+Pnq2LN+4stkMLA0rWUvV5PsQXS # Dj0aqRRbpoYxYqioM+SbOafE9c4deHaUJXPkKqvPnHZL7V/CSxbkS3BMAIke/MV5 # vEwSV/5f4R68Al2o/vsHOE8Nxl2RuQ9nRc3Wg+3nkg2NsWmMT/tZ4CMP0qquAHzu # nEIOz5HXJ7cW7g/DvXwKoO4sCFWFIrjrGBpN/CohrUkxg0eVd3HcsRtLSxwQnHcU # wZ1PL1qVCCkQJjGCBD4wggQ6AgEBMIGJMHUxCzAJBgNVBAYTAklMMRYwFAYDVQQK # Ew1TdGFydENvbSBMdGQuMSkwJwYDVQQLEyBTdGFydENvbSBDZXJ0aWZpY2F0aW9u # IEF1dGhvcml0eTEjMCEGA1UEAxMaU3RhcnRDb20gQ2xhc3MgMiBPYmplY3QgQ0EC # EDm9Qp7SgW661bzJA7S6ZecwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAI # oAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB # CzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFIhPUenCuKHuqDE7qJ58 # Haivq4kRMA0GCSqGSIb3DQEBAQUABIIBAKffoR7G90w4qFR6MwkdWf2dhiL2UcS2 # XyhwDik9EgOb7UYtyEbWwf0hs7BYKvXypAG4wInuVgoGt4Gieg3R0yMgLijI6jvb # 7OFhawAmDDBaX7jWJ7RK4yUGY2WUj37KqIzryvakdS1c7JPxDyI7ZkL8YsryBHxo # pAQMS3Mi47RgfC744rMefWlkWSoocEoc6beANi189ETWZClbeXHehmC91mFJsbDN # PC0FaT1JRq0iesDbP8/f84T3S4VRS8MMe47hY6AaDt6bCsSjm42Rhhrm62DleLaE # ZqSo44dzmhFbWOVvprRWJ6M+Vgtjvzr5qCFyRNhFzCnBSbiaf5vGTnChggIPMIIC # CwYJKoZIhvcNAQkGMYIB/DCCAfgCAQEwdjBiMQswCQYDVQQGEwJVUzEVMBMGA1UE # ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD # VQQDExhEaWdpQ2VydCBBc3N1cmVkIElEIENBLTECEAMBmgI6/1ixa9bV6uYX8GYw # CQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcN # AQkFMQ8XDTE3MDMyMzEzNDExMlowIwYJKoZIhvcNAQkEMRYEFBPE4EZmtDGgS2Y6 # QquGSRluXL8JMA0GCSqGSIb3DQEBAQUABIIBAET0ghtBuvESvMEnkQQ4maM3Pg/g # VcZhM7PFhRj8LavStPxus80irJYxZl3n2rOFqVyOcpu0zYw6ViM8dvFWVbiSjyjJ # dtBU8zPm9hAJST57/lsWgu9i2SD3Y2XJEWy0dmOeAZfjHBjxxj8kO13H6K/RAZ4M # WrD7H8PDMPx37xJq1pwrMgLE+7RQXLaWi8c8svDgOQ8/uIXWKG92d+B8KczX1CqL # bOpZvUo+YptH/YhS48ayWZhJx8+yEW+6MVcLirures0Onbijw4s0R0UbBkUtgz1C # z0yrCCeP7OmigLdSTsbtpWu0CY6pH725iVIWEpIyxjclVHexmIvBUMos8Pg= # SIG # End signature block