<# .SYNOPSIS Sets the recommended TrioFox performance tuning values .DESCRIPTION Sets the recommended TrioFox performance tuning values. 1. Adds/Updates these sections in "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config": 2. Adds/Updates this section in "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Aspnet.config": 3. Calls appcmd.exe to set appConcurrentRequestLimit = 50000 4. Updates these settings in TrioFox's web.config: .EXAMPLE > .\Set-TFPerfTuning.ps1 .NOTES Author: Jeff Reed Name: Set-TFPerfTuning.ps1 Created: 2019-07-22 Version History 2019-07-24 1.0.0 Initial version 2019-08-29 1.0.1 Backup applicationHost.config 2019-08-29 1.0.2 Fix comment based help #> #Requires -Version 5.1 #Requires -RunAsAdministrator #region functions #region New-XMLNode function function New-XMLNode { <# .SYNOPSIS Adds nodes if they don't exist in XML document .DESCRIPTION Adds nodes if they don't exist in XML document .PARAMETER XML An XML document passed in ByRef. The XML will be updated with new nodes. .PARAMETER Parent The parent node of the child node that will be added. This is passed ByRef .PARAMETER Child The child node that will be added #> Param ( [Parameter( Mandatory=$true, ValueFromPipelineByPropertyName=$false )] [ref] $XML, [Parameter( Mandatory=$true, ValueFromPipelineByPropertyName=$false )] [ref] $Parent, [Parameter( Mandatory=$true, ValueFromPipelineByPropertyName=$false )] [String] $Child ) $node = $Parent.Value.SelectNodes($Child) if ($node.Count -eq 0) { $node = $XML.Value.CreateElement($Child) [void] $Parent.Value.AppendChild($node) } $node } #endregion New-XMLNode function #region New-WebConfigAppSetting function New-WebConfigAppSetting { <# .SYNOPSIS Adds (or updates) keys under the appSettings node of web.config .DESCRIPTION Adds (or updates) keys under the appSettings node of web.config .PARAMETER XML An XML document passed in ByRef. The XML will be updated with new keys. .PARAMETER Key The Key to be added, for example "HighDirWorkerCount". .PARAMETER Value The Value to be added (or updated), for example "20" #> Param( [parameter(Mandatory=$true)] [ref] $XML, [parameter(Mandatory=$true)] [string] $Key, [parameter(Mandatory=$true)] [string] $Value ) $node = $xml.Value.configuration.appSettings.add | Where-Object {$_.key -eq $Key} if ($node) { # node exists, update $node.value = $Value } else { # node does not exist, create $newAppSetting = $xml.Value.CreateElement("add") [void] $xml.Value.configuration.appSettings.AppendChild($newAppSetting) $newAppSetting.SetAttribute("key", $Key) $newAppSetting.SetAttribute("value", $Value) } } #endregion New-WebConfigAppSetting function #region Update-MachineCfg function function Update-MachineCfg () { # Defines the path to the .NET 4 machine.config file $machineCfg = Join-Path $env:SystemRoot "\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config" if (-not (Test-Path $machineCfg)) { Throw ("'{0}' does not exist!" -f $machineCfg) } # Read the file as an XML document $xmlMachineCfg = [xml](Get-Content -Path $machineCfg) # Make sure there is a top level configuration node, else throw an error $configuration = $xmlMachineCfg.SelectNodes('/configuration') if ($configuration.Count -eq 0) { Throw ("'configuration' node does not exist in {0}" -f $machineCfg) } # Determine if /configuration/system.web node exists, if not create it $systemWeb = New-XMLNode -XML ([ref] $xmlMachineCfg) -Parent ([ref] $configuration) -Child 'system.web' # Determine if /configuration/system.web/processModel node exists, if not create it $processModel = New-XMLNode -XML ([ref] $xmlMachineCfg) -Parent ([ref] $systemWeb) -Child 'processModel' # Updated processModel attributes $processModel.setattribute("autoConfig", $autoConfig) $processModel.setattribute("maxWorkerThreads", $maxWorkerThreads) $processModel.setattribute("maxIoThreads", $maxIoThreads) $processModel.setattribute("minWorkerThreads", $minWorkerThreads) # Determine if /configuration/system.net node exists, if not create it $systemNet = New-XMLNode -XML ([ref] $xmlMachineCfg) -Parent ([ref] $configuration) -Child 'system.net' # Determine if /configuration/system.net/connectionManagement node exists, if not create it $connectionManagement = New-XMLNode -XML ([ref] $xmlMachineCfg) -Parent ([ref] $systemNet) -Child 'connectionManagement' # Determine if /configuration/system.net/connectionManagement node exists, if not create it $add = New-XMLNode -XML ([ref] $xmlMachineCfg) -Parent ([ref] $connectionManagement) -Child 'add' $add.setattribute("address", "*") $add.setattribute("maxconnection", $maxconnection) # Backup the machine.config file, appending a timestamp to show when the change occurred $now = Get-Date -f "yyyy-MM-dd_hh-mm-ss" Copy-Item -Path $machineCfg -Destination ("{0}_{1}" -f $machineCfg, $now) # Save the updated machine.config file Write-Output ("`nSaving {0}`n" -f $machineCfg) $xmlMachineCfg.Save($machineCfg) } #endregion Update-MachineCfg function #region Update-AspNetCfg function function Update-AspNetCfg () { # Defines the path to the .NET 4 Aspnet.config file $aspNetCfg = Join-Path $env:SystemRoot "\Microsoft.NET\Framework64\v4.0.30319\Aspnet.config" if (-not (Test-Path $aspNetCfg)) { Throw ("'{0}' does not exist!" -f $aspNetCfg) } # Read the file as an XML document $xmlASPNetCfg = [xml](Get-Content -Path $aspNetCfg) # Make sure there is a top level configuration node, else throw an error $configuration = $xmlASPNetCfg.SelectNodes('/configuration') if ($configuration.Count -eq 0) { Throw ("'configuration' node does not exist in {0}" -f $machineCfg) } # Determine if /configuration/system.web node exists, if not create it $systemWeb = New-XMLNode -XML ([ref] $xmlASPNetCfg) -Parent ([ref] $configuration) -Child 'system.web' # Determine if /configuration/system.web/applicationPool node exists, if not create it $applicationPool = New-XMLNode -XML ([ref] $xmlASPNetCfg) -Parent ([ref] $systemWeb) -Child 'applicationPool' # Updated applicationPool attributes $applicationPool.setattribute("maxConcurrentRequestsPerCPU", $maxConcurrentRequestsPerCPU) $applicationPool.setattribute("requestQueueLimit", $requestQueueLimit) # Backup the Aspnet.config file, appending a timestamp to show when the change occurred $now = Get-Date -f "yyyy-MM-dd_hh-mm-ss" Copy-Item -Path $aspNetCfg -Destination ("{0}_{1}" -f $aspNetCfg, $now) # Save the updated Aspnet.config file Write-Output ("Saving {0}`n" -f $aspNetCfg) $xmlASPNetCfg.Save($aspNetCfg) } #endregion Update-AspNetCfg function #region Start-Appcmd function function Start-Appcmd () { # Backup applicationHost.config $appHostConfig = Join-Path $env:SystemRoot "\System32\inetsrv\config\applicationHost.config" $now = Get-Date -f "yyyy-MM-dd_hh-mm-ss" Copy-Item -Path $appHostConfig -Destination ("{0}_{1}" -f $appHostConfig, $now) # Check appcmd.exe path $appcmdExe = Join-Path $env:SystemRoot "\System32\inetsrv\appcmd.exe" if (-not (Test-Path $appcmdExe)) { Throw ("'{0}' does not exist!" -f $appcmdExe) } # "C:\Windows\System32\inetsrv\appcmd.exe" set config -section:system.webServer/serverRuntime /appConcurrentRequestLimit:50000 $argString = "set config `"Default Web Site`" -section:system.webServer/serverRuntime /enabled:`"True`" /appConcurrentRequestLimit:{0} /commit:apphost" -f $appConcurrentRequestLimit $ArgList = $argString.Split(" ") # Write install logs to %temp% $fileErrLog = Join-Path $env:Temp "appcmd_StdErr.log" $fileOutputLog = Join-Path $env:Temp "appcmd_StdOut.log" Write-Output ("Executing: {0} {1}" -f $appCmdExe, $argString) $process = Start-Process -FilePath $appcmdExe -ArgumentList $ArgList -Wait -PassThru -RedirectStandardOutput $fileOutputLog -RedirectStandardError $fileErrLog if ($process.ExitCode -ne 0) { Get-Content $fileErrLog Throw $process.ExitCode } else { Get-Content $fileOutputLog } Write-Output "" } #endregion Start-Appcmd function #region Update-WebCfg function function Update-WebCfg () { # Determine InstallDir # This will return '32-bit' or '64-bit' $osArchitecture = (Get-WmiObject -Class Win32_OperatingSystem).OSArchitecture if ($osArchitecture -eq '64-bit') { # 64 bit $regKey = 'HKLM:\SOFTWARE\Wow6432Node\Gladinet\Enterprise' } else { # 32 bit $regKey = 'HKLM:\SOFTWARE\Gladinet\Enterprise' } $installDir = (Get-ItemProperty -path $regKey -name "InstallDir").InstallDir if ($Null -eq $installDir) { Throw "Failed to retrieve InstallDir registry value. Perhaps TrioFox is not installed." } $webCfg = Join-Path $installDir "\root\web.config" if (-not (Test-Path $webCfg)) { Throw ("'{0}' does not exist!" -f $webCfg) } # Read the file as an XML document $xmlWebCfg = [xml](Get-Content -Path $webCfg) New-WebConfigAppSetting ([ref] $xmlWebCfg ) -Key 'HighDirWorkerCount' -Value $HighDirWorkerCount New-WebConfigAppSetting ([ref] $xmlWebCfg ) -Key 'HighDirMaxQueueLength' -Value $HighDirMaxQueueLength New-WebConfigAppSetting ([ref] $xmlWebCfg ) -Key 'LowDirWorkerCount' -Value $LowDirWorkerCount New-WebConfigAppSetting ([ref] $xmlWebCfg ) -Key 'LowDirMaxQueueLength' -Value $LowDirMaxQueueLength # Backup the web.config file, appending a timestamp to show when the change occurred $now = Get-Date -f "yyyy-MM-dd_hh-mm-ss" Copy-Item -Path $webCfg -Destination ("{0}_{1}" -f $webCfg, $now) Write-Output ("Saving {0}`n" -f $webCfg) $xmlWebCfg.Save($webCfg) } #endregion Update-WebCfg function #endregion functions #region script body #region recommended variable values # These variables are defined at the beginning of the script body in the event they need to be changed in the future. # These are the recommended values for TrioFox tuning in .NET 4 machine.config (strings) $autoConfig = "false" $maxWorkerThreads = "500" $maxIoThreads = "500" $minWorkerThreads = "2" $maxconnection = "20000" # These are recommended values for TrioFox tuning in .NET 4 Aspnet.config (strings) $maxConcurrentRequestsPerCPU = "5000" $requestQueueLimit="20000" # This is the recommended value for the appConcurrentRequestLimit (string value used in appcmd.exe command line) $appConcurrentRequestLimit = "50000" # These are the recommended web.config values (strings) $HighDirWorkerCount = '20' $HighDirMaxQueueLength ='35' $LowDirWorkerCount = '10' $LowDirMaxQueueLength = '15' #endregion recommended variable values # Each change is implemented as separate functions. Update-MachineCfg Update-AspNetCfg Start-Appcmd Update-WebCfg # Reset IIS iisreset #endregion script body # SIG # Begin signature block # MIIkTgYJKoZIhvcNAQcCoIIkPzCCJDsCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUWsGZ+StwOg+T8ik1JQn0AU6P # 5lCggh90MIID7jCCA1egAwIBAgIQfpPr+3zGTlnqS5p31Ab8OzANBgkqhkiG9w0B # AQUFADCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIG # A1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhh # d3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcg # Q0EwHhcNMTIxMjIxMDAwMDAwWhcNMjAxMjMwMjM1OTU5WjBeMQswCQYDVQQGEwJV # UzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xMDAuBgNVBAMTJ1N5bWFu # dGVjIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EgLSBHMjCCASIwDQYJKoZIhvcN # AQEBBQADggEPADCCAQoCggEBALGss0lUS5ccEgrYJXmRIlcqb9y4JsRDc2vCvy5Q # WvsUwnaOQwElQ7Sh4kX06Ld7w3TMIte0lAAC903tv7S3RCRrzV9FO9FEzkMScxeC # i2m0K8uZHqxyGyZNcR+xMd37UWECU6aq9UksBXhFpS+JzueZ5/6M4lc/PcaS3Er4 # ezPkeQr78HWIQZz/xQNRmarXbJ+TaYdlKYOFwmAUxMjJOxTawIHwHw103pIiq8r3 # +3R8J+b3Sht/p8OeLa6K6qbmqicWfWH3mHERvOJQoUvlXfrlDqcsn6plINPYlujI # fKVOSET/GeJEB5IL12iEgF1qeGRFzWBGflTBE3zFefHJwXECAwEAAaOB+jCB9zAd # BgNVHQ4EFgQUX5r1blzMzHSa1N197z/b7EyALt0wMgYIKwYBBQUHAQEEJjAkMCIG # CCsGAQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMBIGA1UdEwEB/wQIMAYB # Af8CAQAwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC50aGF3dGUuY29tL1Ro # YXd0ZVRpbWVzdGFtcGluZ0NBLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCDAOBgNV # HQ8BAf8EBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAXBgNVBAMTEFRpbWVTdGFtcC0y # MDQ4LTEwDQYJKoZIhvcNAQEFBQADgYEAAwmbj3nvf1kwqu9otfrjCR27T4IGXTdf # plKfFo3qHJIJRG71betYfDDo+WmNI3MLEm9Hqa45EfgqsZuwGsOO61mWAK3ODE2y # 0DGmCFwqevzieh1XTKhlGOl5QGIllm7HxzdqgyEIjkHq3dlXPx13SYcqFgZepjhq # IhKjURmDfrYwggSjMIIDi6ADAgECAhAOz/Q4yP6/NW4E2GqYGxpQMA0GCSqGSIb3 # DQEBBQUAMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3Jh # dGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2aWNlcyBD # QSAtIEcyMB4XDTEyMTAxODAwMDAwMFoXDTIwMTIyOTIzNTk1OVowYjELMAkGA1UE # BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMTQwMgYDVQQDEytT # eW1hbnRlYyBUaW1lIFN0YW1waW5nIFNlcnZpY2VzIFNpZ25lciAtIEc0MIIBIjAN # BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomMLOUS4uyOnREm7Dv+h8GEKU5Ow # mNutLA9KxW7/hjxTVQ8VzgQ/K/2plpbZvmF5C1vJTIZ25eBDSyKV7sIrQ8Gf2Gi0 # jkBP7oU4uRHFI/JkWPAVMm9OV6GuiKQC1yoezUvh3WPVF4kyW7BemVqonShQDhfu # ltthO0VRHc8SVguSR/yrrvZmPUescHLnkudfzRC5xINklBm9JYDh6NIipdC6Anqh # d5NbZcPuF3S8QYYq3AhMjJKMkS2ed0QfaNaodHfbDlsyi1aLM73ZY8hJnTrFxeoz # C9Lxoxv0i77Zs1eLO94Ep3oisiSuLsdwxb5OgyYI+wu9qU+ZCOEQKHKqzQIDAQAB # o4IBVzCCAVMwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAO # BgNVHQ8BAf8EBAMCB4AwcwYIKwYBBQUHAQEEZzBlMCoGCCsGAQUFBzABhh5odHRw # Oi8vdHMtb2NzcC53cy5zeW1hbnRlYy5jb20wNwYIKwYBBQUHMAKGK2h0dHA6Ly90 # cy1haWEud3Muc3ltYW50ZWMuY29tL3Rzcy1jYS1nMi5jZXIwPAYDVR0fBDUwMzAx # oC+gLYYraHR0cDovL3RzLWNybC53cy5zeW1hbnRlYy5jb20vdHNzLWNhLWcyLmNy # bDAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtMjAdBgNV # HQ4EFgQURsZpow5KFB7VTNpSYxc/Xja8DeYwHwYDVR0jBBgwFoAUX5r1blzMzHSa # 1N197z/b7EyALt0wDQYJKoZIhvcNAQEFBQADggEBAHg7tJEqAEzwj2IwN3ijhCcH # bxiy3iXcoNSUA6qGTiWfmkADHN3O43nLIWgG2rYytG2/9CwmYzPkSWRtDebDZw73 # BaQ1bHyJFsbpst+y6d0gxnEPzZV03LZc3r03H0N45ni1zSgEIKOq8UvEiCmRDoDR # EfzdXHZuT14ORUZBbg2w6jiasTraCXEQ/Bx5tIB7rGn0/Zy2DBYr8X9bCT2bW+IW # yhOBbQAuOA2oKY8s4bL0WqkBrxWcLC9JG9siu8P+eJRRw4axgohd8D20UaF5Mysu # e7ncIAkTcetqGVvP6KUwVyyJST+5z3/Jvz4iaGNTmr1pdKzFHTx/kuDDvBzYBHUw # ggTTMIIDu6ADAgECAhAqkZhtgcjc5II2bCEKD4GAMA0GCSqGSIb3DQEBCwUAMH8x # CzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0G # A1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEwMC4GA1UEAxMnU3ltYW50ZWMg # Q2xhc3MgMyBTSEEyNTYgQ29kZSBTaWduaW5nIENBMB4XDTE4MDUyMjAwMDAwMFoX # DTIxMDYyMzIzNTk1OVowazELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0Zsb3JpZGEx # GDAWBgNVBAcMD0ZvcnQgTGF1ZGVyZGFsZTEXMBUGA1UECgwOR2xhZGluZXQsIElu # Yy4xFzAVBgNVBAMMDkdsYWRpbmV0LCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOC # AQ8AMIIBCgKCAQEAwO6vB0l/6YHY+R9DNqPYiA+x6IWGL6TQEdumm4G42obsmCpm # tyo037j4dIdBrQT42PPicQB8j5/jX+y/L+RrgE5jYOcQTTGCW71ZboqGudjmJbkK # iXKpDIF+QmNWPfWBIPx58l9pm5JNeZYApHJSN0tv7XtTzFgXj6rgNpIHGogy8oa8 # BL2Q/f4DMgQ3/cEiYpTZsLlq2ZZJBChKQasswU29VA5xmhuhhOXIfNnJgFITijDa # /R7ebrD4Z4NJzjI2Fi2z6jQ7AMtnZ21xnAywU79wMuKVCmhRqXRhAkiCLtsWitVX # GtxEu6OG9dvTW/2ipqVm1923aAh2qs6a18QK9QIDAQABo4IBXTCCAVkwCQYDVR0T # BAIwADAOBgNVHQ8BAf8EBAMCB4AwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3N2 # LnN5bWNiLmNvbS9zdi5jcmwwYQYDVR0gBFowWDBWBgZngQwBBAEwTDAjBggrBgEF # BQcCARYXaHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGQwXaHR0 # cHM6Ly9kLnN5bWNiLmNvbS9ycGEwEwYDVR0lBAwwCgYIKwYBBQUHAwMwVwYIKwYB # BQUHAQEESzBJMB8GCCsGAQUFBzABhhNodHRwOi8vc3Yuc3ltY2QuY29tMCYGCCsG # AQUFBzAChhpodHRwOi8vc3Yuc3ltY2IuY29tL3N2LmNydDAfBgNVHSMEGDAWgBSW # O1PweTOXr32D7y4rzMq3hh5yZjAdBgNVHQ4EFgQUK00KOFsRE4eer7ziBf8iSGJ3 # myYwDQYJKoZIhvcNAQELBQADggEBAHdBodwEeCdWcr0CULLPuBznC+rtOIKO5QQv # IBfsISNLsXvr26jHuKm/hyon3FzzxceINxYeIEf6NxXV59mg4Wcm6UTYmLAPhEog # +YNFWN2/GY42A713bG4b7rp9tqfAWYeMB8tFRip9kvzgJQmPKR3y0s9K/22jNN3v # m6WA5vKJQouzmFJA7IQH17vU3N6gCljOYu0vknMm+0N43E3wUhvwfy5b8KQJLaFz # 6TOQDZZPTnEkOs7l+E+AgX3wB6U7DwjKWWtp58s9ec8av/+/puaVU4LQoJEla8pb # EIT7A1Hlc2n6LTKCRn0bNZ6K+F5kaBifAXNxc8NCovP2tjLAz94wggVZMIIEQaAD # AgECAhA9eNf5dklgsmF99PAeyoYqMA0GCSqGSIb3DQEBCwUAMIHKMQswCQYDVQQG # EwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWdu # IFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA2IFZlcmlTaWduLCBJbmMu # IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENs # YXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH # NTAeFw0xMzEyMTAwMDAwMDBaFw0yMzEyMDkyMzU5NTlaMH8xCzAJBgNVBAYTAlVT # MR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50 # ZWMgVHJ1c3QgTmV0d29yazEwMC4GA1UEAxMnU3ltYW50ZWMgQ2xhc3MgMyBTSEEy # NTYgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC # AQEAl4MeABavLLHSCMTXaJNRYB5x9uJHtNtYTSNiarS/WhtR96MNGHdou9g2qy8h # UNqe8+dfJ04LwpfICXCTqdpcDU6kDZGgtOwUzpFyVC7Oo9tE6VIbP0E8ykrkqsDo # OatTzCHQzM9/m+bCzFhqghXuPTbPHMWXBySO8Xu+MS09bty1mUKfS2GVXxxw7hd9 # 24vlYYl4x2gbrxF4GpiuxFVHU9mzMtahDkZAxZeSitFTp5lbhTVX0+qTYmEgCscw # dyQRTWKDtrp7aIIx7mXK3/nVjbI13Iwrb2pyXGCEnPIMlF7AVlIASMzT+KV93i/X # E+Q4qITVRrgThsIbnepaON2b2wIDAQABo4IBgzCCAX8wLwYIKwYBBQUHAQEEIzAh # MB8GCCsGAQUFBzABhhNodHRwOi8vczIuc3ltY2IuY29tMBIGA1UdEwEB/wQIMAYB # Af8CAQAwbAYDVR0gBGUwYzBhBgtghkgBhvhFAQcXAzBSMCYGCCsGAQUFBwIBFhpo # dHRwOi8vd3d3LnN5bWF1dGguY29tL2NwczAoBggrBgEFBQcCAjAcGhpodHRwOi8v # d3d3LnN5bWF1dGguY29tL3JwYTAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vczEu # c3ltY2IuY29tL3BjYTMtZzUuY3JsMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF # BQcDAzAOBgNVHQ8BAf8EBAMCAQYwKQYDVR0RBCIwIKQeMBwxGjAYBgNVBAMTEVN5 # bWFudGVjUEtJLTEtNTY3MB0GA1UdDgQWBBSWO1PweTOXr32D7y4rzMq3hh5yZjAf # BgNVHSMEGDAWgBR/02Wnwt3su/AwCfNDOfoCrzMxMzANBgkqhkiG9w0BAQsFAAOC # AQEAE4UaHmmpN/egvaSvfh1hU/6djF4MpnUeeBcj3f3sGgNVOftxlcdlWqeOMNJE # WmHbcG/aIQXCLnO6SfHRk/5dyc1eA+CJnj90Htf3OIup1s+7NS8zWKiSVtHITTuC # 5nmEFvwosLFH8x2iPu6H2aZ/pFalP62ELinefLyoqqM9BAHqupOiDlAiKRdMh+Q6 # EV/WpCWJmwVrL7TJAUwnewusGQUioGAVP9rJ+01Mj/tyZ3f9J5THujUOiEn+jf0o # r0oSvQ2zlwXeRAwV+jYrA9zBUAHxoRFdFOXivSdLVL4rhF4PpsN0BQrvl8OJIrEf # d/O9zUPU8UypP7WLhK9k8tAUITCCBZowggOCoAMCAQICCmEZk+QAAAAAABwwDQYJ # KoZIhvcNAQEFBQAwfzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEpMCcGA1UEAxMgTWljcm9zb2Z0IENvZGUgVmVyaWZpY2F0aW9uIFJvb3QwHhcN # MTEwMjIyMTkyNTE3WhcNMjEwMjIyMTkzNTE3WjCByjELMAkGA1UEBhMCVVMxFzAV # BgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO # ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh # dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1 # YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0G # CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7 # K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbext0uz/o9+B1fs70PbZmIV # Yc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhDY2pSS9KP6HBRTdGJ # aXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/Arr0 # PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxp # g8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGj # gcswgcgwEQYDVR0gBAowCDAGBgRVHSAAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0P # BAQDAgGGMB0GA1UdDgQWBBR/02Wnwt3su/AwCfNDOfoCrzMxMzAfBgNVHSMEGDAW # gBRi+wohW39DbhHaCVRQa/XSlnHxnjBVBgNVHR8ETjBMMEqgSKBGhkRodHRwOi8v # Y3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNyb3NvZnRDb2Rl # VmVyaWZSb290LmNybDANBgkqhkiG9w0BAQUFAAOCAgEAgSqCFow0ZyvlA+s0e4yi # o1CK9FWG8R6Mjq597gMZznKVGEitYhH9IP0/RwYBWuLgb4wVLE48alBsCzajz3oN # nEK8XPgZ1WDjaebiI0FnjGiDdiuPk6MqtX++WfupybImj8qi84IbmD6RlSeXhmHu # W10Ha82GqOJlgKjiFeKyviMFaroM80eTTaykjAd5OcBhEjoFDYmj7J9XiYT77Mp8 # R2YUkdi2Dxld5rhKrLxHyHFDluYyIKXcd4b9POOLcdt7mwP8tx0yZOsWUqBDo/ou # rVmSTnzH8jNCSDhROnw4xxskIihAHhpGHxfbGPfwJzVsuGPZzblkXSulXu/GKbTy # x/ghzAS6V/0BtqvGZ/nn05l/9PUi+nL1/f86HEI6ofmAGKXujRzUZp5FAf6q7v/7 # F48w9/HNKcWd7LXVSQA9hbjLu5M6J2pJwDCuZsn3Iygydvmkg1bISM5alqqgzAzE # f7SOl69t41Qnw5+GwNbkcwiXBdvQVGJeA0jC1Z9/p2aM0J2wT9TTmF9Lesl/silS # 0BKAxw9Uth5nzcagbBEDhNNIdecq/rA7bgo6pmt2mQWj8XdoYTMURwb8U39SvZIU # XEokameMr42QqtD2eSEbkyZ8w84evYg4kq5FxhlqSVCzBfiuWTeKaiUDlLFZgVDo # uoOAtyM19Ha5Zx1ZGK0gjZQwggcFMIIE7aADAgECAhBylAQQHz4Mo0eDf8oXWoQ4 # MA0GCSqGSIb3DQEBBQUAMH8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n # dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y # YXRpb24xKTAnBgNVBAMTIE1pY3Jvc29mdCBDb2RlIFZlcmlmaWNhdGlvbiBSb290 # MB4XDTA1MTEwMTEzNDY0NloXDTI1MTEwMTEzNTQwM1owfzELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UEAxMgTWljcm9zb2Z0IENvZGUg # VmVyaWZpY2F0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC # AQC9d8kcfxV4OMUHQyFa++TMO8ZVMfwhibG85wGc+5C+IBFVdqdNAuey9C6N77KH # RlbKR87Iw2PjCANLlga5cCJE5kt7RD91t7imK5EIQe9LB1nWpBmd9suku44CZU3K # 3g+0kCLxtWtcIvbK+TiqKAsGLTwZjbc1X4Pt3WVzhEaSn0TiiUqM1ZinbT3oGctE # rRgL6lxffAvDmpNoRPO2v5eZMHI/KFnQcMgFV3j1SoI0CiTBerBkpTpuEtUDYTi7 # Di39hZzWSHVqHLKi6JH6t+T1PF/9yUCsx6BC9XTYudvX/nN3GuDEtwmxBZpt416A # OHV4UrYS03muQ/dlp9EWZGmFj3g6uJS/RRJiWk2HSNb4GbxZAQb1GttgKZ8BP25z # +f2ARc6V14r2kgzBc0AsbaoypvF/MPiQ8a5FJ7m0DjACvcYO7DyMW7Y0hc8UCwxQ # DaniWZEuqAE59CwVYwSAuEDfYvf+t0wTqCypZhM4YvxAcGJ7dXfVK44bpZnlubfH # reoBoCV7WEZSVlSiyZIrWB1IUcAf/jcA0eKrEMKpWelCmW6PtR5HZnQemHZXVwRe # vS+Fk9UOC58ueyZkp4YSCVBj59HHjn4OOwfnu+TNGkDUeroFWUrW0O7cll4iSicc # RePe2rLp00P96W/AyX0f/Z+QnIYgCMx03ECnKbOrWGVrsQIDAQABo4IBezCCAXcw # CwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFGL7CiFbf0Nu # EdoJVFBr9dKWcfGeMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly9jcmwubWljcm9z # b2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY3Jvc29mdENvZGVWZXJpZlJvb3Qu # Y3JsMBAGCSsGAQQBgjcVAQQDAgEAMHQGA1UdIARtMGswaQYJKwYBBAGCNxUvMFww # WgYIKwYBBQUHAgIwTh5MAEMAbwBwAHkAcgBpAGcAaAB0ACAAqQAgADIAMAAwADUA # IABNAGkAYwByAG8AcwBvAGYAdAAgAEMAbwByAHAAbwByAGEAdABpAG8AbjBZBggr # BgEFBQcBAQRNMEswSQYIKwYBBQUHMAKGPWh0dHA6Ly93d3cubWljcm9zb2Z0LmNv # bS9wa2kvY2VydHMvTWljcm9zb2Z0Q29kZVZlcmlmUm9vdC5jcnQwDQYJKoZIhvcN # AQEFBQADggIBAGFC6OsYyHHcRhlpbeoOzThnrD6nB/ZNFjyeV/u4uKfHhwnmY1fQ # PUaQUPUFmcnKdDr7Aa16TWqrhOBAU1fInNUENoK4tx7Gh5nC2McgnsbyPlX5j3RE # Ud0rttAU3cbe0sX/ha8XuaB12sYN4kV2lhrLPlP76TRbMgMjbL/Yfpo9hQ/IFTud # AFZPr92xJRygzClmG0fOe2fvZO9IR5LenRRQabhfgqnyrZMrU++rYjI36r8EC0br # GYSmqkmgbcGrLYNBarTWQ3vSO3oM0m3QDSDcW8Ipp/iCJCIWATXYGtZEItxHZ1am # aC7/yWaf+3+0ZMYeZ3bgMS462XMNZ5nI9WEeXcGnuI8xHzjf47OHTE2zxPZgXKys # DaAsArnv8KNdJ72WfQ3Q1EAG0aTWy26z1Tb+SMjyOCZWOiBqpMMASOcYKeero6t8 # B6R/pWtKugI/hpdduW5ZJOB8j+3vw8+qrxVRP9/3KHhd600fXTQImzQ7KqHIkQl9 # U8H/fYAf4Gso1LndWHQhuJ8tvRU6TkVKXMOsfAey0CEVuM9p2hTkLCT7ZuUBnhpm # tMStTSutYGLk5I/qNw3K2Dbcf9sgejPAStYfLeCFziuhktdUUyBhhnw3AwOM/ENH # 5PhIi6waQuqYgl1iU4FrU0YwsueFq7wYnIaWWYa2Gq/6/UgxJFwBHLscMYIERDCC # BEACAQEwgZMwfzELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBv # cmF0aW9uMR8wHQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMTAwLgYDVQQD # EydTeW1hbnRlYyBDbGFzcyAzIFNIQTI1NiBDb2RlIFNpZ25pbmcgQ0ECECqRmG2B # yNzkgjZsIQoPgYAwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKEC # gAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwG # CisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFEo+GjJq/FI6nP8MVBHtnzAZetk6 # MA0GCSqGSIb3DQEBAQUABIIBAAYf/sH4lIBzVVhcxP+uYA6Gb/m+ulrIXuDB3FS9 # xDwRevr9771LcWp2WVqJ0Yhj5BgYI0hBWZESCrfOPuWdMSiZ6XgsSuwoCHGGEpmF # qBP1RkEooCHOD+3s3G+8UDpF11Tb2dWRp+XXy/ossOcwG/gQyMpUra9Gc4qoz+Mk # NlhE4bQhyfQVdxLQz5BwzCDkDCv3a4A1PFqy80dSgssD1pdEomjQJkAY+NqfuEzO # rpv7gE3RBawV89bmp4MsrLzQYP0v0vWzt3gecbheW3s1zzSZuwZr3H4sQyTePtjf # Y56gqd9FOyMErOEcm2M0qCeMqcB44uDCnW7sP+DDyN0fbbehggILMIICBwYJKoZI # hvcNAQkGMYIB+DCCAfQCAQEwcjBeMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3lt # YW50ZWMgQ29ycG9yYXRpb24xMDAuBgNVBAMTJ1N5bWFudGVjIFRpbWUgU3RhbXBp # bmcgU2VydmljZXMgQ0EgLSBHMgIQDs/0OMj+vzVuBNhqmBsaUDAJBgUrDgMCGgUA # oF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTkx # MDI0MTgxODI0WjAjBgkqhkiG9w0BCQQxFgQUAQsW5S3qolIlcfn3r4+NqWCDwcww # DQYJKoZIhvcNAQEBBQAEggEAGkCwd8MNtUY9D0i3wNY1e3SKjr/CHeqfA7ryNt7T # 404uvy5eJdjnjtq2qflk/OEDLo2rTs5xfpcVrlUipYhp3Z2DEUXUZdAzTcx0VOeU # G9uCXeazUMIHDhndAozEvBmja0o+iAXhzH5VPeWB/g6+5+iLOPDdPP7Djh4x+I7e # wMeZc3O/knftdL4Y+1q9pUIvhJXuaH80KGbRSXwergvhAZBHVFosasG/X0B6dbmw # oqC3caRDAhEsU3cxPyKfNffJ4F9t7rqph+FUOw5FEyGGwks/VQAYqstYAfW09GpC # BQ6UcV3tx5NkVAggFdxIIHY3hobwvDDZpXcdTU99tmosMQ== # SIG # End signature block