Private/az-commands.ps1
$MAX_RETRY_COUNT = 4 # for some operations, retry a couple of times $SNAILMODE_MAX_RETRY_COUNT = 10 # For very slow tenants, retry more often $script:Snail_Mode = $false $Sleep_Factor = 1 $Snail_Maximum_Sleep_Factor = 90 # times ten is 15 minutes function Convert-LinesToObject { param ( [Parameter(ValueFromPipeline = $true)] [string[]] $Lines ) BEGIN { $linesJsonBuilder = new-object System.Text.StringBuilder } PROCESS { if($null -eq $Lines) { return } $null = $linesJsonBuilder.Append([string]::Concat($Lines)) } END { if($null -eq $Lines) { return } return ConvertFrom-Json $linesJsonBuilder.ToString() } } $PERMISSION_ALREADY_ASSIGNED = "Permission already assigned" function CheckAzOutput($azOutput, $fThrowOnError, $noSecretLeakageWarning = $false) { [String[]]$errorMessages = @() foreach ($outputElement in $azOutput) { if ($null -ne $outputElement) { if ($outputElement.GetType() -eq [System.Management.Automation.ErrorRecord]) { if ($outputElement.ToString().Contains("Permission being assigned already exists on the object")) { # TODO: Does this work in non-English environments? Write-Information "Permission is already assigned when executing $azCommand" Write-Output $PERMISSION_ALREADY_ASSIGNED } elseif ($outputElement.ToString().EndsWith("does not exist or one of its queried reference-property objects are not present.")) { # This indicates we are in a tenant with especially long delays between creation of an object and when it becomes available via Graph (this happens and it seems to be tenant-specific). # Let's go into snail mode and thereby grant Graph more time Write-Warning "Created object is not yet available via MS Graph. Reducing executing speed to give Graph more time." $script:Snail_Mode = $true $Sleep_Factor = 0.8 * $Sleep_Factor + 0.2 * $Snail_Maximum_Sleep_Factor # approximate longer sleep times Write-Verbose "Retrying operations now $SNAILMODE_MAX_RETRY_COUNT times, and waiting for (n * $Sleep_Factor) seconds on n-th retry" } elseif ($outputElement.ToString().Contains("Blowfish") -or $outputElement.ToString().Contains('cryptography on a 32-bit Python')) { Write-Debug "Ignoring expected warning about Blowfish: $outputElement" # Ignore, this is an issue of az 2.45.0 and az 2.45.0-preview } elseif ($outputElement.ToString().StartsWith("WARNING") -or $outputElement.ToString().Contains("UserWarning: ")) { if ($outputElement.ToString().StartsWith("WARNING: The underlying Active Directory Graph API will be replaced by Microsoft Graph API") ` -or $outputElement.ToString().StartsWith("WARNING: This command or command group has been migrated to Microsoft Graph API.")) { Write-Debug "Ignoring expected warning about Graph API migration: $outputElement" # Ignore, we know that } elseif ($outputElement.ToString().StartsWith("WARNING: App settings have been redacted.")) { Write-Debug "Ignoring expected warning about redacted app settings: $outputElement" # Ignore, this is a new behavior of az 2.53.1 and affects the output of az webapp settings set, which we do not use anyway. } elseif ($noSecretLeakageWarning -and $outputElement.ToString().StartsWith("WARNING: [Warning] This output may compromise security by showing")) { Write-Debug "Ignoring expected warning about secret leakage: $outputElement" } else { Write-Debug "Warning about unexpected az output" Write-Warning $outputElement.ToString() } } else { if ($outputElement.ToString().contains("does not have authorization to perform action 'Microsoft.Authorization/roleAssignments/write'")) { $errorMessages += "You have insufficient privileges to assign roles to Managed Identities. Make sure you have the Global Admin or Privileged Role Administrator role." } elseif($outputElement.ToString().Contains("Forbidden")) { $errorMessages += "You have insufficient privileges to complete the operation. Please ensure that you run this CMDlet with required privileges e.g. Global Administrator" } Write-Debug "Error about unexpected az output: $outputElement" $errorMessages += $outputElement } } else { Write-Output $outputElement # add to return value of this function } } } if ($errorMessages.Count -gt 0) { $ErrorMessageOneLiner = [String]::Join("`r`n", $errorMessages) if ($fThrowOnError) { throw $ErrorMessageOneLiner } else { Write-Error $ErrorMessageOneLiner } } } function AzLogin { # Check whether az is available $azCommand = Get-Command az 2>&1 if ($azCommand.GetType() -eq [System.Management.Automation.ErrorRecord]) { if ($azCommand.CategoryInfo.Reason -eq "CommandNotFoundException") { $errorMessage = "Azure CLI (az) is not installed, but required. Please use the Azure Cloud Shell or install Azure CLI as described here: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli" Write-Error $errorMessage throw $errorMessage } else { Write-Error "Unknown error checking for az" throw $azCommand } } # check whether already logged in $env:AZURE_HTTP_USER_AGENT = "pid-a262352f-52a9-4ed9-a9ba-6a2b2478d19b" $account = az account show 2>&1 if ($account.GetType() -eq [System.Management.Automation.ErrorRecord]) { if (($account.ToString().Contains("az login")) -or ($account.ToString().Contains("az account set"))) { Write-Host "Not logged in to az yet. Please log in." $null = az login # TODO: Check whether the login worked AzLogin } else { Write-Error "Error $account while trying to use az" # possibly az not installed? throw $account } } else { try { if ($account[0].GetType() -eq [System.Management.Automation.ErrorRecord] -and ` $account[0].ToString().EndsWith('MGMT_DEPLOYMENTMANAGER') -and $account[0].ToString().StartsWith('ERROR')) { Write-Warning "Ignoring error message from az account show: $($account[0])" # This is a bug in az 2.45.0 (preview?) that causes the first line of the output to be the error message "ERROR: Error loading command module 'deploymentmanager': MGMT_DEPLOYMENTMANAGER" $account = $account[1..$account.Count] } $accountInfo = Convert-LinesToObject($account) } catch { Write-Verbose "Raw output from az account show: $account" Write-Error "Error parsing output from az account show:�n$_" throw $_ } Write-Information "Logged in to az as $($accountInfo.user.name)" } return $accountInfo } $azVersionInfo = $null function GetAzVersion { if ($null -eq $azVersionInfo) { $azVersionInfo = Convert-LinesToObject -lines $(az version) } return $azVersionInfo } function AzUsesAADGraph { $cliVersion = [Version]::Parse((GetAzVersion).'azure-cli') return $cliVersion -lt '2.37' } # Check heuristically whether we are in Azure Cloud Shell function IsAzureCloudShell { $cloudShellProves = 0 # The more proves, the more likely we are in Azure Cloud Shell. We use a 2 out of 3 vote. $azuredrive = get-psdrive -Name Azure -ErrorAction Ignore if ($null -ne $azuredrive) { ++$cloudShellProves } $cloudDrive = Get-ChildItem -Path ~\clouddrive if ($null -ne $cloudDrive) { ++$cloudShellProves } if ($PSVersionTable.Platform -eq "Unix") { ++$cloudShellProves } return $cloudShellProves -ge 2 } # It is intended to use for az cli add permissions and az cli add permissions admin # $azCommand - The command to execute. # $noSecretLeakageWarning - Pass true if you are sure that the output contains no secrets. This will supress az warnings about leaking secrets in the output. function ExecuteAzCommandRobustly($azCommand, $principalId = $null, $appRoleId = $null, $GraphBaseUri = $null, [switch]$callAzNatively, [switch]$noSecretLeakageWarning) { $azErrorCode = 1234 # A number not null $retryCount = 0 $script:Snail_Mode = $false try { $definedPreference = $PSNativeCommandUseErrorActionPreference $PSNativeCommandUseErrorActionPreference = $false # See https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7.3#psnativecommanduseerroractionpreference while ($azErrorCode -ne 0 -and ($retryCount -le $MAX_RETRY_COUNT -or $script:Snail_Mode -and $retryCount -le $SNAILMODE_MAX_RETRY_COUNT)) { $PreviousErrorActionPreference = $ErrorActionPreference $ErrorActionPreference = "Continue" # In Windows PowerShell, if this is set to "Stop", az will not return the error code, but instead throw an exception if ($callAzNatively) { $lastAzOutput = az $azCommand 2>&1 } else { $lastAzOutput = Invoke-Expression "$azCommand 2>&1" # the output is often empty in case of error :-(. az just writes to the console then } $azErrorCode = $LastExitCode $ErrorActionPreference = $PreviousErrorActionPreference Write-Debug "az command $azCommand returned with error code $azErrorCode" try { $lastAzOutput = CheckAzOutput -azOutput $lastAzOutput -fThrowOnError $true -noSecretLeakageWarning $noSecretLeakageWarning # If we were requested to check that the permission is there and there was no error, do the check now. # However, if the permission has been there previously already, we can skip the check if($null -ne $appRoleId -and $azErrorCode -eq 0 -and $PERMISSION_ALREADY_ASSIGNED -ne $lastAzOutput) { $appRoleAssignments = Convert-LinesToObject -lines $(az rest --method get --url "$GraphBaseUri/v1.0/servicePrincipals/$principalId/appRoleAssignments") $grantedPermission = $appRoleAssignments.value | Where-Object { $_.appRoleId -eq $appRoleId } if ($null -eq $grantedPermission) { $azErrorCode = 999 # A number not 0 } } elseif ($null -ne $appRoleId -and $PERMISSION_ALREADY_ASSIGNED -eq $lastAzOutput) { $azErrorCode = 0 # The permission was already there, so we are done. Ignore the error message that the permission was already there. } } catch { Write-Warning $_ $azErrorCode = 654 # a number not 0 if ($_.Contains("Failed to connect to MSI. Please make sure MSI is configured correctly") -and $_.Contains("400")) { if (IsAzureCloudShell) { Write-Warning "Trying to log in again to Azure CLI, as this usually fixes the token issue in Azure Cloud Shell" az login } } } if ($azErrorCode -ne 0) { ++$retryCount Write-Verbose "Retry $retryCount for $azCommand after $($retryCount * $SLEEP_FACTOR) seconds of sleep because Error Code is $azErrorCode" Start-Sleep ($retryCount * $SLEEP_FACTOR) # Sleep for some seconds, as the grant sometimes only works after some time } } } finally { $PSNativeCommandUseErrorActionPreference = $definedPreference } if ($azErrorCode -ne 0 ) { if ($null -eq $lastAzOutput) { $readableAzOutput = "no az output" } else { # might be an object[] $readableAzOutput = CheckAzOutput -azOutput $lastAzOutput -fThrowOnError $false } Write-Error "Error $azErrorCode when executing $azCommand : $readableAzOutput" throw "Error $azErrorCode when executing $azCommand : $readableAzOutput" } else { return $lastAzOutput } } function HashTable2AzJson($psHashTable) { $output = ConvertTo-Json -Compress -InputObject $psHashTable -Depth 10 if ($PSVersionTable.PSVersion.Major -lt 7 -or ($PSVersionTable.PSVersion.Major -eq 7 -and $PSVersionTable.PSVersion.Minor -lt 3) ` -or $PSVersionTable.OS.StartsWith("Microsoft Windows")) { # The double quoting is now also required on PS 7.3.0 on Windows ... does it depend on the az version? $output = $output -replace '"', '\"' # The double quoting is required by PowerShell <7.2 (see https://github.com/PowerShell/PowerShell/issues/1995 and https://docs.microsoft.com/en-us/cli/azure/use-cli-effectively?tabs=bash%2Cbash2#use-quotation-marks-in-parameters) return $output.Insert(1,' ') # Seemingly, there needs to be a space in the JSON somewhere in the beginning for PS 5 to pass consecutive spaces to az instead of having space-separated parameters } return $output } # SIG # Begin signature block # MIIvUQYJKoZIhvcNAQcCoIIvQjCCLz4CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCNZGu8kERV/rai # h/Xh8BnzSzpFqDMJhc6WaOL4A7omq6CCFDUwggWQMIIDeKADAgECAhAFmxtXno4h # MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV # BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z # ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB # AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z # G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ # anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s # Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL # 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb # BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3 # JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c # AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx # YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0 # viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL # T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud # EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf # Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk # aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS # PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK # 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB # cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp # 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg # dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri # RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7 # 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5 # nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3 # i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H # EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G # CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C # 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce # 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da # E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T # SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA # FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh # D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM # 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z # 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05 # huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY # mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP # /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T # AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD # VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG # A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV # HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU # cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN # BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry # sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL # IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf # Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh # OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh # dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV # 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j # wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH # Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC # XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l # /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW # eE4wggfpMIIF0aADAgECAhAE0w/ewLw2E3KQ6RwmFyT5MA0GCSqGSIb3DQEBCwUA # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwHhcNMjMxMTE2MDAwMDAwWhcNMjYxMTE1MjM1OTU5WjCB8TET # MBEGCysGAQQBgjc8AgEDEwJERTEXMBUGCysGAQQBgjc8AgECEwZIZXNzZW4xIjAg # BgsrBgEEAYI3PAIBARMRT2ZmZW5iYWNoIGFtIE1haW4xHTAbBgNVBA8MFFByaXZh # dGUgT3JnYW5pemF0aW9uMRIwEAYDVQQFEwlIUkIgMTIzODExCzAJBgNVBAYTAkRF # MQ8wDQYDVQQIEwZIZXNzZW4xGjAYBgNVBAcTEU9mZmVuYmFjaCBhbSBNYWluMRcw # FQYDVQQKEw5nbHVlY2trYW5qYSBBRzEXMBUGA1UEAxMOZ2x1ZWNra2FuamEgQUcw # ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDOkzyWiAT0dzoCrdo4dTaE # UjIJKcht/Gvb3OOJ/WpNQYJius0XbgOcyBu+7+yGANG0SKDbGxuy8gl6FDMkMKXS # g4ukpw2GLeMNATJ+MBd5FL3MwTSyZS0SljlAbIdyo7ydBeCNrCqKsJoBLARTdxSu # fsxRtgsEOM3AqkT51Z+oSb3fOpAvG3E6fj6ViQP2C37m3t9LvCzNJO6TQ94ylKFg # WxOLmHlBnvBEK6wLsL3FRWl0avXTNvheH7XmY7vI9Othb469+V+FJVBbmD7SE0f5 # miAND4wpNGObz76r2TsHFcgTHah8EGKTJeo0+m3AM158ILT2cN35v8z7X4RbJ7L5 # k4eMFNoWKwPc72UPZKdlo0OQuutL5ehtFhopnB7WUUFCNV4+KQGYo9cKEeufGqV0 # xrIcdH409ejAuMleNZ4CLyU5LE5qVkYxLgdjDdCdxbk2ADSTOwQtpLJExnhf/jkc # 9sRTys9i6NtpE+hb6xbAJ7p4vQt3iLMDQHy6l98HNJNlmY3Phvk0ViUIzRC7qgv7 # Fe+5bE6FkFc/J4rrx6AUTJek/WvkhbvJp39IvspHUxTYC34l9y8Dcnxk3XU2TASn # JR6yKElD+OetRKE0rS9VcuL7kJrTY9det5Kv1hzoZj3zPqd5X+cqqV5hzE3aI3TP # 1v0zICGYf5ayeA1zg9aCkQIDAQABo4ICAjCCAf4wHwYDVR0jBBgwFoAUaDfg67Y7 # +F8Rhvv+YXsIiGX0TkIwHQYDVR0OBBYEFOTb7LJoGHhU5+5fcQSNJKUzQX0kMD0G # A1UdIAQ2MDQwMgYFZ4EMAQMwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdp # Y2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD # AzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3JsMy5kaWdpY2VydC5jb20v # RGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0Ex # LmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1 # c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwgZQGCCsG # AQUFBwEBBIGHMIGEMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j # b20wXAYIKwYBBQUHMAKGUGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp # Q2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0 # MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggIBAMkcpd3bsp6QPtw6hZFySq8n # 50F0KYvrGH0MnQipkz7lV5RvFjl/cBf5gRSrebMIV1rvQMttrFxC06Y3zTbU6t4E # z1nDX76GZV7bmomreROITlH43UvsYacedTmiPp+SFDF5hjDz71XHaATzaSSL5puE # GRrGCyEh2Y/tw823jtk7jDLZrjb74kbGIB21/uUkjOWkhNGN55rDa933sjJuoZx2 # /pVSSmHxo+Bvc3td67EY4ylZj4CsBHmr6afeGKtZFT/QtnilYq+5nARiCDVKSHP0 # svNpmOCDZJg+aaq+TBAtvu6ddAogZ4FHtpOFQ+NQZeO9jWNn/9bYDdBlwejQKPqZ # 0p3oO+25FyYe8dxr1j82TyefL4mC486nVbSSk3XCu+LUKRmMkOh8cSKXyIP06RIz # LWQSpS1zenI+DREJ6VJHI/pBhRZGr9i6gwOIVaKva2t/AnaCkI4ulJd8iq6/lI+z # DvuLPjRqQOv2+Zf+1jbNV2I0BttmiFfXGDeAOCEaiF82lak6CcwkrGj3Hbt7YjuF # Zd7qCJWHG4pVrpJhwEScp+1+kDLpWGlupiPJv4XDhKUEqJPQ2KGhMzE0JDd8V7Si # 4gXvAoEZAPb1sjLcatDHYJX1acsAHEoYD2Um1Lx0pARy4LcHsTPrETz4EiiGg/iE # qeoXQDjtJraR++BTJXQyMYIacjCCGm4CAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUG # A1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQg # RzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAE0w/ewLw2 # E3KQ6RwmFyT5MA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKA # AKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIGCaHehTJsjCLCRd6ZxKPoqJ # RHaj3z6U2x77SYyzs2KhMA0GCSqGSIb3DQEBAQUABIICAMONSgcAfEM9tA1yAhj9 # J1EzGdCXFb2PTdLTXpcfUKgu+8JHh75GoxvfVM/1YYQQuDMYjDey0I/9mvlforXx # rPeAk3zZ7zOmi0QFa7pwhJwp0Tqq+N9JVtyHqVj03xbsqsjYgJdHDHgoBn98uk3T # +BtXhLRHxed0JmgeHe3FmBID2AZOStQH3u1KfVirBPICWpjAtzhzNAdh976IXC8V # VFh05kATvHeL7a0KrFHi9wqbmy4YLcn+bIEw2fJhZ00RRPRojO1SGoz82BVXxBBw # /RquWWDWb++TTiVuolh9VYHl0baWn8zGD8NdVPQhIEjOrCJIaMTDRTsdGnKErQCZ # YrmceTLGl91kmn02M7nWZnucrcxwsSxLVSnG2lxS2M+UXB6sBpaiO/mQviaYH4wa # JBlPyAAB6o6yAuHkbsQGvrDWrLUgbcNO/UGAAvSfLJr6ZHz/IfVx9qwijG69+Jae # Eh/PlhKTix/qjWW8gudaUmW7S9/FGeerX0cdRiW/rkeTt3ecEzMHgR4Ug/c4tnjU # nkjePK/t3FSlmcBMPQX3T41a93uPZB3/dVj3bM4VXaRN6Oz0Mk4ygcHBx1Udw7gl # MDtSeYtLFh5ocnnC5aAWeTjvmWeuvsa/2Dq1bn3y8olomIUVz2WX8jBRw2m3RkWP # 2VOoLUUGc3+E4bQdfjBnwYDNoYIXPzCCFzsGCisGAQQBgjcDAwExghcrMIIXJwYJ # KoZIhvcNAQcCoIIXGDCCFxQCAQMxDzANBglghkgBZQMEAgEFADB3BgsqhkiG9w0B # CRABBKBoBGYwZAIBAQYJYIZIAYb9bAcBMDEwDQYJYIZIAWUDBAIBBQAEIJ0wecQq # /3d/59NXrtldN7R7c87b8q1N8DTj7mXdEdR8AhBONvNhL0aSfnsHlNFii0A0GA8y # MDI0MDIyODEyMDUzOVqgghMJMIIGwjCCBKqgAwIBAgIQBUSv85SdCDmmv9s/X+Vh # FjANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl # cnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBT # SEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTIzMDcxNDAwMDAwMFoXDTM0MTAxMzIz # NTk1OVowSDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSAw # HgYDVQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMzCCAiIwDQYJKoZIhvcNAQEB # BQADggIPADCCAgoCggIBAKNTRYcdg45brD5UsyPgz5/X5dLnXaEOCdwvSKOXejsq # nGfcYhVYwamTEafNqrJq3RApih5iY2nTWJw1cb86l+uUUI8cIOrHmjsvlmbjaedp # /lvD1isgHMGXlLSlUIHyz8sHpjBoyoNC2vx/CSSUpIIa2mq62DvKXd4ZGIX7ReoN # YWyd/nFexAaaPPDFLnkPG2ZS48jWPl/aQ9OE9dDH9kgtXkV1lnX+3RChG4PBuOZS # lbVH13gpOWvgeFmX40QrStWVzu8IF+qCZE3/I+PKhu60pCFkcOvV5aDaY7Mu6QXu # qvYk9R28mxyyt1/f8O52fTGZZUdVnUokL6wrl76f5P17cz4y7lI0+9S769SgLDSb # 495uZBkHNwGRDxy1Uc2qTGaDiGhiu7xBG3gZbeTZD+BYQfvYsSzhUa+0rRUGFOpi # CBPTaR58ZE2dD9/O0V6MqqtQFcmzyrzXxDtoRKOlO0L9c33u3Qr/eTQQfqZcClhM # AD6FaXXHg2TWdc2PEnZWpST618RrIbroHzSYLzrqawGw9/sqhux7UjipmAmhcbJs # ca8+uG+W1eEQE/5hRwqM/vC2x9XH3mwk8L9CgsqgcT2ckpMEtGlwJw1Pt7U20clf # CKRwo+wK8REuZODLIivK8SgTIUlRfgZm0zu++uuRONhRB8qUt+JQofM604qDy0B7 # AgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNV # HSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgB # hv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8wHQYDVR0OBBYE # FKW27xPn783QZKHVVqllMaPe1eNJMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9j # cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZU # aW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUFBzAB # hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6Ly9j # YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEy # NTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIBAIEa1t6gqbWY # F7xwjU+KPGic2CX/yyzkzepdIpLsjCICqbjPgKjZ5+PF7SaCinEvGN1Ott5s1+Fg # nCvt7T1IjrhrunxdvcJhN2hJd6PrkKoS1yeF844ektrCQDifXcigLiV4JZ0qBXqE # KZi2V3mP2yZWK7Dzp703DNiYdk9WuVLCtp04qYHnbUFcjGnRuSvExnvPnPp44pMa # dqJpddNQ5EQSviANnqlE0PjlSXcIWiHFtM+YlRpUurm8wWkZus8W8oM3NG6wQSbd # 3lqXTzON1I13fXVFoaVYJmoDRd7ZULVQjK9WvUzF4UbFKNOt50MAcN7MmJ4ZiQPq # 1JE3701S88lgIcRWR+3aEUuMMsOI5ljitts++V+wQtaP4xeR0arAVeOGv6wnLEHQ # mjNKqDbUuXKWfpd5OEhfysLcPTLfddY2Z1qJ+Panx+VPNTwAvb6cKmx5AdzaROY6 # 3jg7B145WPR8czFVoIARyxQMfq68/qTreWWqaNYiyjvrmoI1VygWy2nyMpqy0tg6 # uLFGhmu6F/3Ed2wVbK6rr3M66ElGt9V/zLY4wNjsHPW2obhDLN9OTH0eaHDAdwrU # AuBcYLso/zjlUlrWrBciI0707NMX+1Br/wd3H3GXREHJuEbTbDJ8WC9nR2XlG3O2 # mflrLAZG70Ee8PBf4NvZrZCARK+AEEGKMIIGrjCCBJagAwIBAgIQBzY3tyRUfNhH # rP0oZipeWzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQD # ExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIwMzIzMDAwMDAwWhcNMzcw # MzIyMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu # Yy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYg # VGltZVN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA # xoY1BkmzwT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCwzIP5WvYRoUQVQl+kiPNo # +n3znIkLf50fng8zH1ATCyZzlm34V6gCff1DtITaEfFzsbPuK4CEiiIY3+vaPcQX # f6sZKz5C3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ7Gnf2ZCHRgB720RBidx8 # ald68Dd5n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7QKxfst5Kfc71ORJn7w6l # Y2zkpsUdzTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/tePc5OsLDnipUjW8LAxE6lX # KZYnLvWHpo9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCYOjgRs/b2nuY7W+yB3iIU # 2YIqx5K/oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9KoRxrOMUp88qqlnNCaJ+2 # RrOdOqPVA+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6dSgkQe1CvwWcZklSUPRR # 8zZJTYsg0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM1+mYSlg+0wOI/rOP015L # dhJRk8mMDDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbCdLI/Hgl27KtdRnXiYKNY # CQEoAA6EVO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbECAwEAAaOCAV0wggFZMBIG # A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1NhS9zKXaaL3WMaiCPnshv # MB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIB # hjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUH # MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDov # L2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQw # QwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lD # ZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZI # AYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7ZvmKlEIgF+ZtbYIULhsBgu # EE0TzzBTzr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI2AvlXFvXbYf6hCAlNDFn # zbYSlm/EUExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/tydBTX/6tPiix6q4XNQ1/t # YLaqT5Fmniye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVPulr3qRCyXen/KFSJ8NWK # cXZl2szwcqMj+sAngkSumScbqyQeJsG33irr9p6xeZmBo1aGqwpFyd/EjaDnmPv7 # pp1yr8THwcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc6UsCUqc3fpNTrDsdCEkP # lM05et3/JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3cHXg65J6t5TRxktcma+Q4 # c6umAU+9Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0dKNPH+ejxmF/7K9h+8kad # dSweJywm228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZPJ/tgZxahZrrdVcA6KYaw # mKAr7ZVBtzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLeMt8EifAAzV3C+dAjfwAL # 5HYCJtnwZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDyDivl1vupL0QVSucTDh3b # NzgaoSv27dZ8/DCCBY0wggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZI # hvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ # MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNz # dXJlZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVow # YjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ # d3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290 # IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjww # IjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J5 # 8soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMH # hOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6 # Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQ # ecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4b # A3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9 # WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCU # tNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvo # ZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/J # vNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCP # orF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMB # Af8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXr # oq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRt # MGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEF # BQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl # ZElEUm9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgw # BgYEVR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cH # vZqsoYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8 # UgPITtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTn # f+hZqPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxU # jG/voVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8j # LfR+cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDGCA3Yw # ggNyAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu # MTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRp # bWVTdGFtcGluZyBDQQIQBUSv85SdCDmmv9s/X+VhFjANBglghkgBZQMEAgEFAKCB # 0TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTI0 # MDIyODEyMDUzOVowKwYLKoZIhvcNAQkQAgwxHDAaMBgwFgQUZvArMsLCyQ+CXc6q # isnGTxmcz0AwLwYJKoZIhvcNAQkEMSIEIDKgz72b5ygHtEQichyDs6ZqfzVBQHrF # mopxqna4phQ5MDcGCyqGSIb3DQEJEAIvMSgwJjAkMCIEINL25G3tdCLM0dRAV2hB # Nm+CitpVmq4zFq9NGprUDHgoMA0GCSqGSIb3DQEBAQUABIICAETDjpt+97UiABiC # JWHP+bgG0Z3bNfCcllliOUw1hGFLYBc8cLQz9GouFVMpiY3gCW1/a/gJlrD4aLSo # ZkdJFUUiocRk1fvyS3Wh5MUOVMKmPDA2gkuNzjbwcXZ11Q5dSq1G4XcOvoY56YlC # 44/rH3vdJtZJm13nTUXECmN2T1YIxAQjKRruYzAXiUGBJ0KBaS5CHVfLE/QiN7Ax # gXgjKPq8ig7WCUSbwdmb7SBLOdun/hY0lmyljAYGZmwQ/i1CyISf+Y2GeJMv0gEP # SQERlc8ebNeX9JTtN/5JpKRP7lnaUBv1/aEWC6tkVHcuScvcUX93pQ6C6JFv5C3V # c0b8pDmefFMnHw1TiJuGAwwfPgP3wY9OHMTF+X6lupi8IRCUpCOmXOF5CVETtJBJ # 0TzTk42omjHvueh9YnyjgWUfKmbk7q6hXPxzt+o/h1bv/aAn9GHpgPFXCSPMXpD/ # UagOfW+jOakhtnwvYWkKWnCf+cvoUkFuVdhqkd1OTbLW5nZWqZrlsxD4U3HIOGz3 # 8eYBuGGpty3Eml1qU8YOKfzNms9qXxjnspX0lKtY72by+2f5tb10cBW9aHYbxu8Z # 4azp6LTaULYrx5GR8w2WFk7DFlaI4BtXJVW6DP4oY45Evs41vMmVhb5rSafW/JkP # x7swSe7pGxqycSIMAWD6unI8nN/1 # SIG # End signature block |