Framework/BugLog/AutoCloseBugManager.ps1
Set-StrictMode -Version Latest class AutoCloseBugManager { hidden [string] $OrganizationName; hidden [PSObject] $ControlSettings; hidden [string] $ScanSource; hidden [bool] $UseAzureStorageAccount = $false; hidden [BugLogHelper] $BugLogHelperObj; AutoCloseBugManager([string] $orgName) { $this.OrganizationName = $orgName; $this.ControlSettings = [ConfigurationManager]::LoadServerConfigFile("ControlSettings.json"); $this.ScanSource = [AzSKSettings]::GetInstance().GetScanSource(); if ([Helpers]::CheckMember($this.ControlSettings.BugLogging, "UseAzureStorageAccount", $null)) { $this.UseAzureStorageAccount = $this.ControlSettings.BugLogging.UseAzureStorageAccount; if ($this.UseAzureStorageAccount) { $this.BugLogHelperObj = [BugLogHelper]::BugLogHelperInstance if (!$this.BugLogHelperObj) { $this.BugLogHelperObj = [BugLogHelper]::GetInstance($this.OrganizationName); } } } } #function to auto close resolved bugs hidden [void] AutoCloseBug([SVTEventContext []] $ControlResults) { #tags that need to be searched $TagSearchKeyword = "" #flag to check number of current keywords in the tag $QueryKeyWordCount = 0; #maximum no of keywords that need to be checked per batch $MaxKeyWordsToQuery=0; #all passing control results go here $PassedControlResults = @(); $autoCloseOrgBugFlag=$true $autoCloseProjBugFlag=$true; try { $MaxKeyWordsToQuery = $this.ControlSettings.BugLogging.MaxKeyWordsToQueryForBugClose; $autoCloseOrgBugFlag=$this.ControlSettings.BugLogging.AutoCloseOrgBug $autoCloseProjBugFlag=$this.ControlSettings.BugLogging.AutoCloseProjectBug } catch { $MaxKeyWordsToQuery=30 $autoCloseOrgBugFlag=$true $autoCloseProjBugFlag=$true; } #collect all passed control results $ControlResults | ForEach-Object { if ($_.ControlResults[0].VerificationResult -eq "Passed") { #to check if org level bugs should be auto closed based on control settings if($_.FeatureName -eq "Organization"){ if($autoCloseOrgBugFlag -eq $true){ $PassedControlResults += $_ } } #to check if proj level bugs should be auto closed based on control settings elseif($_.FeatureName -eq "Project"){ if($autoCloseProjBugFlag -eq $true){ $PassedControlResults += $_ } } else { $PassedControlResults += $_ } } } #number of passed controls $PassedControlResultsLength = ($PassedControlResults | Measure-Object).Count #the following loop will call api for bug closing in batches of size as defined in control settings, #first check if passed controls length is less than the batch size, if yes then we have to combine all tags in one go #and call the api #if length is more divide the control results in chunks of batch size, after a particular batch is made call the api #reinitialize the variables for the next batch $PassedControlResults | ForEach-Object { $control = $_; #if control results are less than the maximum no of tags per batch if ($PassedControlResultsLength -lt $MaxKeyWordsToQuery) { #check for number of tags in current query $QueryKeyWordCount++; if ($this.UseAzureStorageAccount -and $this.ScanSource -eq "CA") { #complete the query $TagSearchKeyword += "(ADOScannerHashId eq '" + $this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) + "') or " #if the query count equals the passing control results, search for bugs for this batch if ($QueryKeyWordCount -eq $PassedControlResultsLength) { #to remove OR from the last tag keyword. Ex: Tags: Tag1 OR Tags: Tag2 OR. Remove the last OR from this keyword $TagSearchKeyword = $TagSearchKeyword.Substring(0, $TagSearchKeyword.length - 3) $response = $this.BugLogHelperObj.GetTableEntityAndCloseBug($TagSearchKeyword) } } else { #complete the query $TagSearchKeyword += "Tags: " + $this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) + " OR " #if the query count equals the passing control results, search for bugs for this batch if ($QueryKeyWordCount -eq $PassedControlResultsLength) { #to remove OR from the last tag keyword. Ex: Tags: Tag1 OR Tags: Tag2 OR. Remove the last OR from this keyword $TagSearchKeyword = $TagSearchKeyword.Substring(0, $TagSearchKeyword.length - 3) $response = $this.GetWorkItemByHash($TagSearchKeyword,$MaxKeyWordsToQuery) #if bug was present if ($response[0].results.count -gt 0) { $response.results | ForEach-Object { #close the bug $id = $_.fields."system.id" $Project = $_.project.name $this.CloseBug($id, $Project) } } } } } #if the number of control results was more than batch size else { $QueryKeyWordCount++; if ($this.UseAzureStorageAccount -and $this.ScanSource -eq "CA") { $TagSearchKeyword += "(ADOScannerHashId eq '" + $this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) + "') or " #if number of tags reaches batch limit if ($QueryKeyWordCount -eq $MaxKeyWordsToQuery) { #query for all these tags and their bugs $TagSearchKeyword = $TagSearchKeyword.Substring(0, $TagSearchKeyword.length - 3) $response = $this.BugLogHelperObj.GetTableEntityAndCloseBug($TagSearchKeyword); #Reinitialize for the next batch $QueryKeyWordCount = 0; $TagSearchKeyword = ""; $PassedControlResultsLength -= $MaxKeyWordsToQuery } } else { $TagSearchKeyword += "Tags: " + $this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) + " OR " #if number of tags reaches batch limit if ($QueryKeyWordCount -eq $MaxKeyWordsToQuery) { #query for all these tags and their bugs $TagSearchKeyword = $TagSearchKeyword.Substring(0, $TagSearchKeyword.length - 3) $response = $this.GetWorkItemByHash($TagSearchKeyword,$MaxKeyWordsToQuery) if ($response[0].results.count -gt 0) { $response.results.values | ForEach-Object { $id = ($_.fields | where { $_.name -eq "ID" }).value $Project = $_.project $this.CloseBug($id, $Project) } } #Reinitialize for the next batch $QueryKeyWordCount = 0; $TagSearchKeyword = ""; $PassedControlResultsLength -= $MaxKeyWordsToQuery } } } } } #function to close an active bug hidden [void] CloseBug([string] $id, [string] $Project) { $url = "https://dev.azure.com/{0}/{1}/_apis/wit/workitems/{2}?api-version=6.0" -f $this.OrganizationName, $Project, $id #load the closed bug template $BugTemplate = [ConfigurationManager]::LoadServerConfigFile("TemplateForClosedBug.Json") $BugTemplate = $BugTemplate | ConvertTo-Json -Depth 10 $header = [WebRequestHelper]::GetAuthHeaderFromUriPatch($url) try { $responseObj = Invoke-RestMethod -Uri $url -Method Patch -ContentType "application/json-patch+json ; charset=utf-8" -Headers $header -Body $BugTemplate } catch { Write-Host "Could not close the bug" -ForegroundColor Red } } #function to retrieve all new/active/resolved bugs hidden [object] GetWorkItemByHash([string] $hash,[int] $MaxKeyWordsToQuery) { $url = "https://almsearch.dev.azure.com/{0}/_apis/search/workitemsearchresults?api-version=6.0-preview.1" -f $this.OrganizationName #take results have been doubled, as their might be chances for a bug to be logged more than once, if the tag id is copied. #in this case we want all the instances of this bug to be closed $body = '{"searchText": "{0}","$skip": 0,"$top": 60,"filters": {"System.TeamProject": [],"System.WorkItemType": ["Bug"],"System.State": ["New","Active","Resolved"]}}'| ConvertFrom-Json $body.searchText = $hash $response = [WebRequestHelper]:: InvokePostWebRequest($url, $body) return $response } #function to create hash for bug tag hidden [string] GetHashedTag([string] $ControlId, [string] $ResourceId) { $hashedTag = $null $stringToHash = "$ResourceId#$ControlId"; #return the bug tag if ($this.UseAzureStorageAccount -and $this.ScanSource -eq "CA") { return [AutoBugLog]::ComputeHashX($stringToHash); } else { return "ADOScanID: " + [AutoBugLog]::ComputeHashX($stringToHash) } } } # SIG # Begin signature block # MIIjkQYJKoZIhvcNAQcCoIIjgjCCI34CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDjdSfNidlbp8u5 # jmlC39tO61OhiBnqRJVU+0wqXcbXdaCCDYEwggX/MIID56ADAgECAhMzAAAB32vw # LpKnSrTQAAAAAAHfMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjAxMjE1MjEzMTQ1WhcNMjExMjAyMjEzMTQ1WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQC2uxlZEACjqfHkuFyoCwfL25ofI9DZWKt4wEj3JBQ48GPt1UsDv834CcoUUPMn # s/6CtPoaQ4Thy/kbOOg/zJAnrJeiMQqRe2Lsdb/NSI2gXXX9lad1/yPUDOXo4GNw # PjXq1JZi+HZV91bUr6ZjzePj1g+bepsqd/HC1XScj0fT3aAxLRykJSzExEBmU9eS # yuOwUuq+CriudQtWGMdJU650v/KmzfM46Y6lo/MCnnpvz3zEL7PMdUdwqj/nYhGG # 3UVILxX7tAdMbz7LN+6WOIpT1A41rwaoOVnv+8Ua94HwhjZmu1S73yeV7RZZNxoh # EegJi9YYssXa7UZUUkCCA+KnAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUOPbML8IdkNGtCfMmVPtvI6VZ8+Mw # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDYzMDA5MB8GA1UdIwQYMBaAFEhu # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAnnqH # tDyYUFaVAkvAK0eqq6nhoL95SZQu3RnpZ7tdQ89QR3++7A+4hrr7V4xxmkB5BObS # 0YK+MALE02atjwWgPdpYQ68WdLGroJZHkbZdgERG+7tETFl3aKF4KpoSaGOskZXp # TPnCaMo2PXoAMVMGpsQEQswimZq3IQ3nRQfBlJ0PoMMcN/+Pks8ZTL1BoPYsJpok # t6cql59q6CypZYIwgyJ892HpttybHKg1ZtQLUlSXccRMlugPgEcNZJagPEgPYni4 # b11snjRAgf0dyQ0zI9aLXqTxWUU5pCIFiPT0b2wsxzRqCtyGqpkGM8P9GazO8eao # mVItCYBcJSByBx/pS0cSYwBBHAZxJODUqxSXoSGDvmTfqUJXntnWkL4okok1FiCD # Z4jpyXOQunb6egIXvkgQ7jb2uO26Ow0m8RwleDvhOMrnHsupiOPbozKroSa6paFt # VSh89abUSooR8QdZciemmoFhcWkEwFg4spzvYNP4nIs193261WyTaRMZoceGun7G # CT2Rl653uUj+F+g94c63AhzSq4khdL4HlFIP2ePv29smfUnHtGq6yYFDLnT0q/Y+ # Di3jwloF8EWkkHRtSuXlFUbTmwr/lDDgbpZiKhLS7CBTDj32I0L5i532+uHczw82 # oZDmYmYmIUSMbZOgS65h797rj5JJ6OkeEUJoAVwwggd6MIIFYqADAgECAgphDpDS # AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla # MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT # H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG # OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S # 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz # y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7 # 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u # M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33 # X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl # XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP # 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB # l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF # RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM # CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ # BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud # DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO # 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw # cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA # XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY # 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj # 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd # d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ # Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf # wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ # aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j # NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B # xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 # eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 # r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I # RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVZjCCFWICAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAd9r8C6Sp0q00AAAAAAB3zAN # BglghkgBZQMEAgEFAKCBsDAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgG7+7Kw+n # /YU85s3mtp9W35etm42UFh0+stvINuzOndswRAYKKwYBBAGCNwIBDDE2MDSgFIAS # AE0AaQBjAHIAbwBzAG8AZgB0oRyAGmh0dHBzOi8vd3d3Lm1pY3Jvc29mdC5jb20g # MA0GCSqGSIb3DQEBAQUABIIBAIBVSOJOB3hsMkf78mJpYhUqlUo53UcE0bt02O9z # 12KmQOpJqesyAVgJ46V4hcqUizlUib8QuhRcHpUUSB5JfBhtKs3lE33oC/5Idguw # hBqpAlb80cir83PEQY+9YWB7duQVTB6ILYW6vi1rua4RRpB7uY747CmaB4bqwKA7 # w2KIknjzn5U+HpclkXpsclpLiVGMIOVTxhuVSrR/zWyDusv6j0ziY1AiwqOCun3a # 5zCDGhFehidc7ntcLE6y/MQ8poZ11FYIqYsmwna4WECt2WMCtJM4Io4e5lbahcrO # xknfmF495TTQOqTUNenBTWU6zQvJ5i5jR2Yk1Vn+Wm86AouhghLuMIIS6gYKKwYB # BAGCNwMDATGCEtowghLWBgkqhkiG9w0BBwKgghLHMIISwwIBAzEPMA0GCWCGSAFl # AwQCAQUAMIIBVQYLKoZIhvcNAQkQAQSgggFEBIIBQDCCATwCAQEGCisGAQQBhFkK # AwEwMTANBglghkgBZQMEAgEFAAQg0eFnYeaILW1mk7c8IZseVzGmMUZUJ5Mk4L42 # T/uQXyoCBmA9A3BxjxgTMjAyMTAzMTUwMjMxMDcuMzYzWjAEgAIB9KCB1KSB0TCB # zjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl # ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMg # TWljcm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxl # cyBUU1MgRVNOOjg5N0EtRTM1Ni0xNzAxMSUwIwYDVQQDExxNaWNyb3NvZnQgVGlt # ZS1TdGFtcCBTZXJ2aWNloIIOQTCCBPUwggPdoAMCAQICEzMAAAFgByDwkkjavusA # AAAAAWAwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw # MTAwHhcNMjEwMTE0MTkwMjIwWhcNMjIwNDExMTkwMjIwWjCBzjELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWljcm9zb2Z0IE9w # ZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjg5 # N0EtRTM1Ni0xNzAxMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2 # aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtDGAHNDyxszxUjM+ # CY31NaRazaTxLUJlTI3nxIvMtbfXnytln87iXrwZvhKQT+IFRKTjJV6wEo5Widss # vecDAheaxiGfkFHRFc8j1cuLPNWqyVSAc/NM9G0y1m76O3KAKmHkx+q4GJr9KnQe # OPuUQOs0dH8L/X/EJpnJCmAhHuUBEkhpFWHnL5apuqZtSwUigXlQfDDMkUmk5fFi # 0DS5a6toql0JTMDOHrCQpmAyRGtc/cT/DlyzhTtxiJiNlEaWbcav68mCTJOwpbc4 # GJO2Rpb96O2lb5Lqm7817NcWoDPC5ION4giY454Rq+UD071WkJ7GjXPpUKmnQRvf # 3Ti6EwIDAQABo4IBGzCCARcwHQYDVR0OBBYEFKebHvi3qBfgmuF1Mgl1fNDrvh9j # MB8GA1UdIwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJ # oEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01p # Y1RpbVN0YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYB # BQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGlt # U3RhUENBXzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYI # KwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggEBABU0mAibOgWmiVB1Tydh1xfvJKUo # Q/fn2qDlD9IWnt7iPl0DVX6Sy+Yp1kHWOGOwGzYiY04i3I1ja7Y3CNrgk3EV/7bL # 8pNw/wYT3sfyiCv1z5VvW4cXuC2d7cXy+e/QJvv0riZuGLpLRAiGo9wjxzfpSp4/ # AowubfYn6873C4pbY0ry/1sDmBC73YCPq5/sAYC41gciHSJmiT5ty4mlg8opjWe9 # LYRrWDOYXwn+Ks9jgxby/j+Bp6Qmix+RzqBuiZrjDWAUMYqAqG/u2VPX7ne4cZHZ # NLWoxh43AZ8a2OJPFDUGVARmJuTs8V8J74pGFNFMJG3NadKDc0QTTLaoudQwggZx # MIIEWaADAgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQg # Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVa # Fw0yNTA3MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n # dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y # YXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIB # IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mU # a3RUENWlCgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZ # sTBED/FgiIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4Yy # hB50YWeRX4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQ # YrFd/XcfPfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDa # TgaRtogINeh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQID # AQABo4IB5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDz # Q3t8RhvFM2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQE # AwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQ # W9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNv # bS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBa # BggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0 # LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNV # HSABAf8EgZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggr # BgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQA # ZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2d # o6Ehb7Prpsz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GC # RBL7uVOMzPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZ # eUqRUgCvOA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8y # Sif9Va8v/rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOc # o6I8+n99lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz3 # 9L9+Y1klD3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSY # Ighh2rBQHm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvY # grRyzR30uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98is # TtoouLGp25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8 # l1Bx16HSxVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzV # s341Hgi62jbb01+P3nSISRKhggLPMIICOAIBATCB/KGB1KSB0TCBzjELMAkGA1UE # BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc # BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWljcm9zb2Z0 # IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNO # Ojg5N0EtRTM1Ni0xNzAxMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT # ZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQD7MpJ0dYtE3MiXKodXFdmAqdnQoqCBgzCB # gKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV # BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBBQUA # AgUA4/ilKDAiGA8yMDIxMDMxNDE5MDcyMFoYDzIwMjEwMzE1MTkwNzIwWjB0MDoG # CisGAQQBhFkKBAExLDAqMAoCBQDj+KUoAgEAMAcCAQACAggbMAcCAQACAhK5MAoC # BQDj+faoAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEA # AgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQEFBQADgYEAN++5aLXcKoprxnTg # mg92K0+mLV1BNwZUr00g+DQRs5gWG5Uo4pJmPdF1EgpzyyhKZFMyh285uzq0rA1/ # cmwcHo2rZRHpZcXONBkWn4qXdrZAwfaka9xC37h1ZY3rcRwYQKp/+D0xqapeN0+N # Dg4lBWDIQaX7C/xpI7z7+5la/hAxggMNMIIDCQIBATCBkzB8MQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGlt # ZS1TdGFtcCBQQ0EgMjAxMAITMwAAAWAHIPCSSNq+6wAAAAABYDANBglghkgBZQME # AgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJ # BDEiBCCCZPntGIMsoYIb/jJm3S8bhTCL3Dzmb34IHIbH9yPZvTCB+gYLKoZIhvcN # AQkQAi8xgeowgecwgeQwgb0EIAISo72jcy6XW0Wnrx7qK8p+ldL/j1wXCeJeSPeo # sGW5MIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAFg # ByDwkkjavusAAAAAAWAwIgQgA5Vbe+7qvMKL2xMXW4CuVbfPRMvIOOUHAAoEVFkO # +DUwDQYJKoZIhvcNAQELBQAEggEAcL3PKfwoCSvdHZwBAImMr7M1S+QOzsL92jBy # DzGcVXFD+crSs84kIpBjl7SXG6/7Hf2ouLmFFa+DD6OlleGSe3ICTZtNIZBGyYas # Fu/6FPOgjZPANh5z/AYKT/ujYaISBwaLMgQBQNsQNVSoxiNQi+zF2dxuSbJKjMLZ # wnG8NtepHyc1wVw1L5ZIuxSaM71yWGvB47tX2RJqVbso7CY37Zzj4VzAbczkHFzD # fLXiOSFzNq3Td4tNuDSRtnyng/l1vzLl+q3KGi0dQzXdmxesaM6kg7vO6JeTLqeX # UiBiwuCqwSYT13reviq+vOckyfbn8mNky+0z4zg3n9uzcIIaIQ== # SIG # End signature block |