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; static [SVTEventContext []] $ClosedBugs=$null; 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; [AutoCloseBugManager]::ClosedBugs=$null 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 #This Hash map is used to map an ADOScan hashtag value to a control. $hashToControlIDMap=@{} #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 #ToDo add common method for both if and else condition if ($PassedControlResultsLength -lt $MaxKeyWordsToQuery) { #check for number of tags in current query $QueryKeyWordCount++; if ($this.UseAzureStorageAccount -and $this.ScanSource -eq "CA") { $tagHash=$this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) $hashToControlIDMap.add($tagHash,$control); #complete the query $TagSearchKeyword += "(ADOScannerHashId eq '" + $tagHash + "') 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) $closedBugsResponse = $this.BugLogHelperObj.GetTableEntityAndCloseBug($TagSearchKeyword) if ($closedBugsResponse){ $this.closedBugInfoCollect($closedBugsResponse, $hashToControlIDMap) } } } else { $tagHash=$this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) $hashToControlIDMap.add($tagHash,$control); $TagSearchKeyword += "Tags: " + $tagHash + " 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) { $ids = @(); $ids += $response.results.fields."system.id"; $closedBugsResponse = $this.CloseBugsInBulk($ids); #$response.results | ForEach-Object { # #close the bug # $id = $_.fields."system.id" # $Project = $_.project.name # $this.CloseBug($id, $Project) #} if ($closedBugsResponse){ $this.closedBugInfoCollect($closedBugsResponse, $hashToControlIDMap) } } } } } #if the number of control results was more than batch size else { $QueryKeyWordCount++; if ($this.UseAzureStorageAccount -and $this.ScanSource -eq "CA") { $tagHash=$this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) $hashToControlIDMap.add($tagHash,$control); $TagSearchKeyword += "(ADOScannerHashId eq '" + $tagHash + "') 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) $closedBugsResponse = $this.BugLogHelperObj.GetTableEntityAndCloseBug($TagSearchKeyword); if ($closedBugsResponse){ $this.closedBugInfoCollect($closedBugsResponse, $hashToControlIDMap) } #Reinitialize for the next batch $QueryKeyWordCount = 0; $TagSearchKeyword = ""; $PassedControlResultsLength -= $MaxKeyWordsToQuery $hashToControlIDMap.Clear(); } } else { $tagHash=$this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) $hashToControlIDMap.add($tagHash,$control); $TagSearchKeyword += "Tags: " + $tagHash + " 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) { $ids = @(); $ids += $response.results.fields."system.id"; $closedBugsResponse = $this.CloseBugsInBulk($ids); #$response.results | ForEach-Object { # $id = $_.fields."system.id" # $Project = $_.project.name # $this.CloseBug($id, $Project) #} if ($closedBugsResponse){ $this.closedBugInfoCollect($closedBugsResponse, $hashToControlIDMap) } } #Reinitialize for the next batch $QueryKeyWordCount = 0; $TagSearchKeyword = ""; $PassedControlResultsLength -= $MaxKeyWordsToQuery $hashToControlIDMap.Clear(); } } } } $hashToControlIDMap.Clear(); $hashToControlIDMap=$null Remove-Variable hashToControlIDMap; } #function to auto close resolved bugs hidden [void] AutoCloseBugCSV([SVTEventContext []] $PassedControlResults) { #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; $autoCloseOrgBugFlag=$true $autoCloseProjBugFlag=$true; [AutoCloseBugManager]::ClosedBugs=$null try { $MaxKeyWordsToQuery = $this.ControlSettings.BugLogging.MaxKeyWordsToQueryForBugClose; $autoCloseOrgBugFlag=$this.ControlSettings.BugLogging.AutoCloseOrgBug $autoCloseProjBugFlag=$this.ControlSettings.BugLogging.AutoCloseProjectBug } catch { $MaxKeyWordsToQuery=30 $autoCloseOrgBugFlag=$true $autoCloseProjBugFlag=$true; } #number of passed controls $PassedControlResultsLength = ($PassedControlResults | Measure-Object).Count #This Hash map is used to map an ADOScan hashtag value to a control. $hashToControlIDMap=@{} $PassedControlResults | ForEach-Object { $control = $_; #if control results are less than the maximum no of tags per batch #ToDo add common method for both if and else condition if ($PassedControlResultsLength -lt $MaxKeyWordsToQuery) { #check for number of tags in current query $QueryKeyWordCount++; if ($this.UseAzureStorageAccount ) { $tagHash=$this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) $hashToControlIDMap.add($tagHash,$control); #complete the query $TagSearchKeyword += "(ADOScannerHashId eq '" + $tagHash + "') 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) $closedBugsResponse = $this.BugLogHelperObj.GetTableEntityAndCloseBug($TagSearchKeyword) if ($closedBugsResponse){ $this.closedBugInfoCollect($closedBugsResponse, $hashToControlIDMap) } } } else { $tagHash=$this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) $hashToControlIDMap.add($tagHash,$control); $TagSearchKeyword += "Tags: " + $tagHash + " 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) { $ids = @(); $ids += $response.results.fields."system.id"; $closedBugsResponse = $this.CloseBugsInBulk($ids); if ($closedBugsResponse){ $this.closedBugInfoCollect($closedBugsResponse, $hashToControlIDMap) } } } } } #if the number of control results was more than batch size else { $QueryKeyWordCount++; if ($this.UseAzureStorageAccount ) { $tagHash=$this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) $hashToControlIDMap.add($tagHash,$control); $TagSearchKeyword += "(ADOScannerHashId eq '" + $tagHash + "') 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) $closedBugsResponse = $this.BugLogHelperObj.GetTableEntityAndCloseBug($TagSearchKeyword); if ($closedBugsResponse){ $this.closedBugInfoCollect($closedBugsResponse, $hashToControlIDMap) } #Reinitialize for the next batch $QueryKeyWordCount = 0; $TagSearchKeyword = ""; $PassedControlResultsLength -= $MaxKeyWordsToQuery $hashToControlIDMap.Clear(); } } else { $tagHash=$this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) $hashToControlIDMap.add($tagHash,$control); $TagSearchKeyword += "Tags: " + $tagHash + " 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) { $ids = @(); $ids += $response.results.fields."system.id"; $closedBugsResponse = $this.CloseBugsInBulk($ids); if ($closedBugsResponse){ $this.closedBugInfoCollect($closedBugsResponse, $hashToControlIDMap) } } #Reinitialize for the next batch $QueryKeyWordCount = 0; $TagSearchKeyword = ""; $PassedControlResultsLength -= $MaxKeyWordsToQuery $hashToControlIDMap.Clear(); } } } } $hashToControlIDMap.Clear(); $hashToControlIDMap=$null Remove-Variable hashToControlIDMap; } #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 close an active bugs in bulk hidden [object] CloseBugsInBulk([string[]] $ids) { try { $closeBugTemplate = @(); foreach ($id in $ids) { $closeBugTemplate += [PSCustomObject] @{ method = 'PATCH'; uri = "/_apis/wit/workitems/$($id)?api-version=4.1"; headers = @{"Content-Type" = 'application/json-patch+json'}; body = @(@{op = "add"; "path"= "/fields/System.State"; "value"= "Closed"}; @{op = "add"; "path"= "/fields/Microsoft.VSTS.Common.ResolvedReason"; "value"= ""}) } } if ($closeBugTemplate.count -gt 0) { $body = $null; if ($closeBugTemplate.count -eq 1) { $body = "[$($closeBugTemplate | ConvertTo-Json -depth 10)]" } else { $body = $closeBugTemplate | ConvertTo-Json -depth 10 } $uri = 'https://{0}.visualstudio.com/_apis/wit/$batch?api-version=4.1' -f $this.OrganizationName $header = [WebRequestHelper]::GetAuthHeaderFromUriPatch($uri) $adoResult = Invoke-RestMethod -Uri $uri -Method Patch -ContentType "application/json" -Headers $header -Body $body if ($adoResult -and $adoResult.count -gt 0) { return $adoResult.value; } } return $false; } catch { Write-Host $_ Write-Host "Could not close the bug." -ForegroundColor Red return $false } } hidden [void] closedBugInfoCollect([object] $closedBugsResponse, [hashtable] $hashToControlIDMap){ # Hash map checks for duplicate work items $hashClosedBugs=@{} $closedBugsResponse| ForEach-Object{ #Store closed bug details $bug=$_.body |ConvertFrom-Json $controlHashValue=$null #Fetch hash From storage account CA response if($this.UseAzureStorageAccount -and $this.ScanSource -eq "CA"){ $controlHashValue=$bug.ADOScannerHashID } #Fetch hash for regular scan else{ $controlHashValue=$bug.fields.'System.Tags' } if ($hashToControlIDMap.ContainsKey($controlHashValue) -and $bug.fields.'System.State' -eq 'Closed') { $id=$bug.id $project=$bug.fields.'System.TeamProject' $urlClose= "https://dev.azure.com/{0}/{1}/_workitems/edit/{2}" -f $this.OrganizationName, $project , $id; $hashToControlIDMap[$controlHashValue].ControlResults.AddMessage("Closed Bug",$urlClose); # duplicate work items do not populate static variable $ClosedBugs multiple times if(!$hashClosedBugs.ContainsKey($controlHashValue)){ [AutoCloseBugManager]::ClosedBugs+=$hashToControlIDMap[$controlHashValue] $hashClosedBugs.add($controlHashValue,$true) } } } $hashClosedBugs.Clear() } #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 # MIInvAYJKoZIhvcNAQcCoIInrTCCJ6kCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBLdifIkUN2ZtHE # R83Q14Y8U4drfqwivnjPOhkhVs4mUaCCDYEwggX/MIID56ADAgECAhMzAAACUosz # qviV8znbAAAAAAJSMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjEwOTAyMTgzMjU5WhcNMjIwOTAxMTgzMjU5WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDQ5M+Ps/X7BNuv5B/0I6uoDwj0NJOo1KrVQqO7ggRXccklyTrWL4xMShjIou2I # sbYnF67wXzVAq5Om4oe+LfzSDOzjcb6ms00gBo0OQaqwQ1BijyJ7NvDf80I1fW9O # L76Kt0Wpc2zrGhzcHdb7upPrvxvSNNUvxK3sgw7YTt31410vpEp8yfBEl/hd8ZzA # v47DCgJ5j1zm295s1RVZHNp6MoiQFVOECm4AwK2l28i+YER1JO4IplTH44uvzX9o # RnJHaMvWzZEpozPy4jNO2DDqbcNs4zh7AWMhE1PWFVA+CHI/En5nASvCvLmuR/t8 # q4bc8XR8QIZJQSp+2U6m2ldNAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUNZJaEUGL2Guwt7ZOAu4efEYXedEw # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDY3NTk3MB8GA1UdIwQYMBaAFEhu # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAFkk3 # uSxkTEBh1NtAl7BivIEsAWdgX1qZ+EdZMYbQKasY6IhSLXRMxF1B3OKdR9K/kccp # kvNcGl8D7YyYS4mhCUMBR+VLrg3f8PUj38A9V5aiY2/Jok7WZFOAmjPRNNGnyeg7 # l0lTiThFqE+2aOs6+heegqAdelGgNJKRHLWRuhGKuLIw5lkgx9Ky+QvZrn/Ddi8u # TIgWKp+MGG8xY6PBvvjgt9jQShlnPrZ3UY8Bvwy6rynhXBaV0V0TTL0gEx7eh/K1 # o8Miaru6s/7FyqOLeUS4vTHh9TgBL5DtxCYurXbSBVtL1Fj44+Od/6cmC9mmvrti # yG709Y3Rd3YdJj2f3GJq7Y7KdWq0QYhatKhBeg4fxjhg0yut2g6aM1mxjNPrE48z # 6HWCNGu9gMK5ZudldRw4a45Z06Aoktof0CqOyTErvq0YjoE4Xpa0+87T/PVUXNqf # 7Y+qSU7+9LtLQuMYR4w3cSPjuNusvLf9gBnch5RqM7kaDtYWDgLyB42EfsxeMqwK # WwA+TVi0HrWRqfSx2olbE56hJcEkMjOSKz3sRuupFCX3UroyYf52L+2iVTrda8XW # esPG62Mnn3T8AuLfzeJFuAbfOSERx7IFZO92UPoXE1uEjL5skl1yTZB3MubgOA4F # 8KoRNhviFAEST+nG8c8uIsbZeb08SeYQMqjVEmkwggd6MIIFYqADAgECAgphDpDS # 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/BvW1taslScxMNelDNMYIZkTCCGY0CAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAlKLM6r4lfM52wAAAAACUjAN # BglghkgBZQMEAgEFAKCBsDAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgiO5tMj3M # 1bPPA2/2nOlIVD7/HkeRAaK8vgRbV49p2H8wRAYKKwYBBAGCNwIBDDE2MDSgFIAS # AE0AaQBjAHIAbwBzAG8AZgB0oRyAGmh0dHBzOi8vd3d3Lm1pY3Jvc29mdC5jb20g # MA0GCSqGSIb3DQEBAQUABIIBAEVG0MdP+n0NI3+/VeJwK03ivBF0yfIHXFZRcsvk # 8czGZE/Z8shcn/Y2fBa98TkOVJeWLMNryab+LlKnadq/wXDjsTodG5lWvwHJPKkQ # pJIXn7BG4YlcEL9keEihQmpA8YV1/7gvBKrfdYzY3A7rauUFPUMnvk1keTv7d7Xz # zCh/n++eg8mpj+U1s/OJeS+IPc8+XO08YYrM/C9pI2G78SLmPN/GTeKKzbrPFUJ2 # QChMv5akAMreoyWKGNhpy17wZvtDQF4t/IqSCAkfRmSOaAtcfrO9pMt+ChJEXkM8 # Zp7GLEb5An501MM0pET8hyoxwJUloVePwGn3qcto2Chx6wOhghcZMIIXFQYKKwYB # BAGCNwMDATGCFwUwghcBBgkqhkiG9w0BBwKgghbyMIIW7gIBAzEPMA0GCWCGSAFl # AwQCAQUAMIIBWQYLKoZIhvcNAQkQAQSgggFIBIIBRDCCAUACAQEGCisGAQQBhFkK # AwEwMTANBglghkgBZQMEAgEFAAQgNE7Umul5gj0mQi2QHl8SqFv0p1fjUEtSj9DW # qBkWb2UCBmGVXmDP3RgTMjAyMTEyMTQxMTU2NDIuNzU2WjAEgAIB9KCB2KSB1TCB # 0jELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl # ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMk # TWljcm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1U # aGFsZXMgVFNTIEVTTjo4RDQxLTRCRjctQjNCNzElMCMGA1UEAxMcTWljcm9zb2Z0 # IFRpbWUtU3RhbXAgU2VydmljZaCCEWgwggcUMIIE/KADAgECAhMzAAABiC7NxoFB # 4bwqAAEAAAGIMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv # ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD # QSAyMDEwMB4XDTIxMTAyODE5Mjc0MFoXDTIzMDEyNjE5Mjc0MFowgdIxCzAJBgNV # BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w # HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29m # dCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRT # UyBFU046OEQ0MS00QkY3LUIzQjcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0 # YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa5xAI # BCaRxcfIOtXhLzxV4mDZcao0pxamytqlEoVZyGGMux/8z1c31uDOcs3jwFc8C06X # Ch50HaQ3htl08/cp1E1tirW00VSHxSeaMIKv4KMuWuKAdyZLRH6uw3aAExeUsRmH # Zb8I64P1U4uxvY/aMOnjfdXitQABRbzYzuuDzV3c5xy077VdbWHcS1tC1LpASTDo # Ngi699fsDDyNcdmewy6A/xkDWi2mulM1SH/NFYLsInIHPKZAgNIJ1aFV8PiyHF75 # GzrVrF/bttODkf9X9KQ132HMzo2r/LY6MMqsu2432FLnfnr26FM1B4CEBUN94ekT # OUy+1c7JfoxOZ7eOcd0c+PoYtP0AxEisB/3qE9g6I8QG8e2uDoymIjf6Xo2VtI6z # Xr8VN6WNPX6x2xYa0VNm95r2kCpXVoHv3loOSZnqxGbmO12dVrN+hasd3e8N6Hfl # ZXTy9bhOU58RxXb4ptqKs/FoWQnj62Wwn4x+xU6JOv9mcOBoxoefPOiB6UjcCh8N # T0hNsyRO1PGss/KBNtF21um2ucvMGfaPNHhMl+RCj6HNa5oy7k60xmIpXYjkw7Sb # WYq5QCCir7jjYvDwJC6P0QLYXydNslvY1xQOD7vh2AmKz8/wFr86uXFb5OuBzpM8 # bEI61Pvf1Sp6yW9YPqs1DpQQ71/u9YOSF3a+2wIDAQABo4IBNjCCATIwHQYDVR0O # BBYEFGR5tVDEo7vOu736jbsaM+WMyUpKMB8GA1UdIwQYMBaAFJ+nFV0AXmJdg/Tl # 0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly93d3cubWljcm9zb2Z0 # LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAy # MDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4wXAYIKwYBBQUHMAKGUGh0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVGltZS1T # dGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAww # CgYIKwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggIBAEAQWtv7WAgmy/8YotLbNq+b # Z6TXvuaTjK7oG5LpWIi4vR7bRg3Z11d6JSER2GTcVG2j8YP3eTlIjI0npf6ny5Aw # 7Ejbdg5J3ITMsnCHv5+27Qh/zLfHoAnRLV3XY5nt+xiqWMdR5xyd5L0NaqKkeTy4 # zybZlsGFGdQ3wziKqDiugkaZkpn0VzxntkcmAz3uLt8jID2EkfTXvPblasMmXFqk # Pl2YzI3LPN8BWpoHJ6YKgGfhWREIY0hLHTFGVxv3dboQ2EkXU0GMyXdwpUQdbh3x # jQ1mGl1cO14uT0eBsnJ4IjZ830YGsJLUHVqT7X3g8aJkovz6C0rs2isCgAxC8WRi # CsetYJh+NXo+i4Lc34DrA4GtyRU4dP09QgMrkAMIfhmtpCJ15L0sP+KYoczcjiJr # M+ShwdwUcH3Kjl32Uwln6mcABaCVBCMxaFSqcT+WUD4SqNs7SUDGWZS1WKhVSzCF # PekroOMVFcz8tTHBO225/PXMGMQuREhny4LLViQzF8EXASiz9AUiUNoVK9SfgiJZ # kDdUt8ASPLnWInAraNIgfD7VuMIj4UEdwJNEfak/f6HkOVDkBn929x82sBM/XDDP # bkivwqAo5sdEIhgfhUjZWuY5uhIcUbv0lsd2Q9VKN8vFO5OyiHkXOhTW3m6sbSvC # 6WhlkVnFOSvF/JOSG+aMMIIHcTCCBVmgAwIBAgITMwAAABXF52ueAptJmQAAAAAA # FTANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw # b3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0 # aG9yaXR5IDIwMTAwHhcNMjEwOTMwMTgyMjI1WhcNMzAwOTMwMTgzMjI1WjB8MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy # b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCAiIwDQYJKoZIhvcNAQEBBQADggIP # ADCCAgoCggIBAOThpkzntHIhC3miy9ckeb0O1YLT/e6cBwfSqWxOdcjKNVf2AX9s # SuDivbk+F2Az/1xPx2b3lVNxWuJ+Slr+uDZnhUYjDLWNE893MsAQGOhgfWpSg0S3 # po5GawcU88V29YZQ3MFEyHFcUTE3oAo4bo3t1w/YJlN8OWECesSq/XJprx2rrPY2 # vjUmZNqYO7oaezOtgFt+jBAcnVL+tuhiJdxqD89d9P6OU8/W7IVWTe/dvI2k45GP # sjksUZzpcGkNyjYtcI4xyDUoveO0hyTD4MmPfrVUj9z6BVWYbWg7mka97aSueik3 # rMvrg0XnRm7KMtXAhjBcTyziYrLNueKNiOSWrAFKu75xqRdbZ2De+JKRHh09/SDP # c31BmkZ1zcRfNN0Sidb9pSB9fvzZnkXftnIv231fgLrbqn427DZM9ituqBJR6L8F # A6PRc6ZNN3SUHDSCD/AQ8rdHGO2n6Jl8P0zbr17C89XYcz1DTsEzOUyOArxCaC4Q # 6oRRRuLRvWoYWmEBc8pnol7XKHYC4jMYctenIPDC+hIK12NvDMk2ZItboKaDIV1f # MHSRlJTYuVD5C4lh8zYGNRiER9vcG9H9stQcxWv2XFJRXRLbJbqvUAV6bMURHXLv # jflSxIUXk8A8FdsaN8cIFRg/eKtFtvUeh17aj54WcmnGrnu3tz5q4i6tAgMBAAGj # ggHdMIIB2TASBgkrBgEEAYI3FQEEBQIDAQABMCMGCSsGAQQBgjcVAgQWBBQqp1L+ # ZMSavoKRPEY1Kc8Q/y8E7jAdBgNVHQ4EFgQUn6cVXQBeYl2D9OXSZacbUzUZ6XIw # XAYDVR0gBFUwUzBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYzaHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMBMG # A1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsG # A1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJc # YmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9z # b2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIz # LmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWlj # cm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0 # MA0GCSqGSIb3DQEBCwUAA4ICAQCdVX38Kq3hLB9nATEkW+Geckv8qW/qXBS2Pk5H # ZHixBpOXPTEztTnXwnE2P9pkbHzQdTltuw8x5MKP+2zRoZQYIu7pZmc6U03dmLq2 # HnjYNi6cqYJWAAOwBb6J6Gngugnue99qb74py27YP0h1AdkY3m2CDPVtI1TkeFN1 # JFe53Z/zjj3G82jfZfakVqr3lbYoVSfQJL1AoL8ZthISEV09J+BAljis9/kpicO8 # F7BUhUKz/AyeixmJ5/ALaoHCgRlCGVJ1ijbCHcNhcy4sa3tuPywJeBTpkbKpW99J # o3QMvOyRgNI95ko+ZjtPu4b6MhrZlvSP9pEB9s7GdP32THJvEKt1MMU0sHrYUP4K # WN1APMdUbZ1jdEgssU5HLcEUBHG/ZPkkvnNtyo4JvbMBV0lUZNlz138eW0QBjloZ # kWsNn6Qo3GcZKCS6OEuabvshVGtqRRFHqfG3rsjoiV5PndLQTHa1V1QJsWkBRH58 # oWFsc/4Ku+xBZj1p/cvBQUl+fpO+y/g75LcVv7TOPqUxUYS8vwLBgqJ7Fx0ViY1w # /ue10CgaiQuPNtq6TPmb/wrpNPgkNWcr4A245oyZ1uEi6vAnQj0llOZ0dFtq0Z4+ # 7X6gMTN9vMvpe784cETRkPHIqzqKOghif9lwY1NNje6CbaUFEMFxBmoQtB1VM1iz # oXBm8qGCAtcwggJAAgEBMIIBAKGB2KSB1TCB0jELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3Bl # cmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo4RDQxLTRC # RjctQjNCNzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIj # CgEBMAcGBSsOAwIaAxUA4TyKzHwgF5U9LB4PzTmXlB16DkKggYMwgYCkfjB8MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy # b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIFAOViy4gw # IhgPMjAyMTEyMTQxNTUxMzZaGA8yMDIxMTIxNTE1NTEzNlowdzA9BgorBgEEAYRZ # CgQBMS8wLTAKAgUA5WLLiAIBADAKAgEAAgIOMgIB/zAHAgEAAgISqDAKAgUA5WQd # CAIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6Eg # oQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBABDB/jBSwhLtl4rO0zYWOn26 # zGmM97z7REv0xizasMadFZhB2yyV+5nCrvXLYHrFZH3W3JG+UUGm8dBmr6J8YiHu # mBjutQcoRN8U2S2TGckb2xisCvun+rhTwzKY5/t9rOSD2Rxg9G/V7O0crcWLUDLa # 4VZbM3JDWsJzlnYHK5GTMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3Rh # bXAgUENBIDIwMTACEzMAAAGILs3GgUHhvCoAAQAAAYgwDQYJYIZIAWUDBAIBBQCg # ggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQg # ZfDXdCeqI31kTWIa5xrA61V/ylzh+fYdDcz1oyanGeIwgfoGCyqGSIb3DQEJEAIv # MYHqMIHnMIHkMIG9BCBm6d7trAY3RoSC+M/snI7c0qXuGy1fwKGGsqZe0klApTCB # mDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAk # BgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABiC7NxoFB # 4bwqAAEAAAGIMCIEIE5h4EVwpqU5BYwseMOcXEa7hC0mpTohv4+JBHumVdnUMA0G # CSqGSIb3DQEBCwUABIICAIoe9dGH34NSPOE/QvStYXBb1wM+bfzI3xNp+6gigMbe # yxL+iGU9J3Ps4G3bul+5QNWEuvEqOCyvuBMtkqMx9gW0d57YWVDAPzmHg4hxXz20 # qNnwMQWiVmc5t0nVQyWI89R7VysRjouk7VjacLZ6f28bTv9DOdVrcrxfNXHSbPTj # KkBYjB2mMcjB4OcesJ7lxhJ+h9srQfP/iFUSTv1N6bmuzotJgGSo79/gn6RwTs1K # hwIo8cTbnLLalul/VU+1qTL+/2xsi/C5/aSXlm1yAL4lnxFmENYZliC0N8A0ZfSg # OtppK8Wkc+dhW/5Ajnh3GfmGZHFAWC5EPx8Yj4iRK4BRZ7/yP5kX8Ux25u51nsoX # dUlyFn98uDDKoPNEKXD8Be5IU5F4gDlqVkZexEIHaU6NODppOd8k1fXTPMQ16/HI # eobvhGwJl6Es5DxA4t4YIMowYhZZQFHmMB8LaxXSS72Li40Qy6YDMPED81k9ykLb # nA7t9aEWq20YN/lDEVfsyuCVAYn2+V7StcJ5UqL11LEFNpPp3hH5RCGGxFQM62zW # pShdatxcD7X8/qqAJSS8ylzdTGIm9ksa3sOdPxssef6pQc6y7ooVYRZWqORy7TH6 # lRS/zT3h7uYiNrzjLqyMuI9nSM8NETQsG49CTZwHkJwjuOApx85kBD23A3PYkbXw # SIG # End signature block |