Engines/Terraform/Invoke-AvmTerraformCheckPolicy.ps1
|
function Invoke-AvmTerraformPolicyExample { [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory)] $Example, [Parameter(Mandatory)] $Options ) Set-StrictMode -Version 3.0 $ErrorActionPreference = 'Stop' $envVars = @{} $primaryError = $null $issues = [System.Collections.Generic.List[object]]::new() $evaluated = 0 try { $Example.CleanupStarted = $true Invoke-AvmScriptHook ` -HookPath (Join-Path $Example.StagedPath 'pre.ps1') ` -WorkingDirectory $Example.StagedPath ` -Label ("policy {0} pre.ps1" -f $Example.Name) $envVars = ConvertFrom-AvmDotEnv -Path (Join-Path $Example.StagedPath '.env') $terraformEnv = Get-AvmTerraformPolicyEnvironment -StageRoot $Example.StageRoot -Environment $envVars $terraformLock = Lock-AvmTerraformPluginCache ` -WorkingDirectory $Example.StagedPath ` -EnvVars $terraformEnv try { Initialize-AvmTerraformPolicyStage ` -TerraformPath $Options.TerraformPath ` -ConftestPath $Options.ConftestPath ` -WorkingDirectory $Example.StagedPath ` -StageRoot $Example.StageRoot ` -EnvVars $terraformEnv $null = Invoke-AvmProcess ` -FilePath $Options.TerraformPath ` -ArgumentList @('plan', '-out=tfplan', '-input=false', '-no-color') ` -WorkingDirectory $Example.StagedPath ` -EnvVars $terraformEnv ` -Label ("terraform plan ({0})" -f $Example.Name) $showResult = Invoke-AvmProcess ` -FilePath $Options.TerraformPath ` -ArgumentList @('show', '-json', 'tfplan') ` -WorkingDirectory $Example.StagedPath ` -EnvVars $terraformEnv ` -Label ("terraform show ({0})" -f $Example.Name) } finally { if ($null -ne $terraformLock) { $terraformLock.Dispose() } } $planJsonPath = Join-Path $Example.StagedPath 'tfplan.json' [System.IO.File]::WriteAllText( $planJsonPath, [string]$showResult.StdOut, [System.Text.UTF8Encoding]::new($false)) $localExceptions = Join-Path $Example.StagedPath 'exceptions' $policyRuns = @( [pscustomobject]@{ Name = 'APRL'; Path = $Options.AprlPath } [pscustomobject]@{ Name = 'AVMSEC'; Path = $Options.AvmsecPath } ) foreach ($policyRun in $policyRuns) { $arguments = [System.Collections.Generic.List[string]]::new() $arguments.Add('test') $arguments.Add('--all-namespaces') $arguments.Add('--policy') $arguments.Add([string]$policyRun.Path) $arguments.Add('--policy') $arguments.Add($Options.DefaultExceptions) if (Test-Path -LiteralPath $localExceptions -PathType Container) { $arguments.Add('--policy') $arguments.Add($localExceptions) } $arguments.Add('--output') $arguments.Add('json') $arguments.Add('tfplan.json') $policyResult = Invoke-AvmProcess ` -FilePath $Options.ConftestPath ` -ArgumentList $arguments.ToArray() ` -WorkingDirectory $Example.StagedPath ` -EnvVars $envVars ` -Label ("conftest {0} ({1})" -f $policyRun.Name, $Example.Name) ` -IgnoreExitCode $parsed = ConvertFrom-AvmPolicyResult ` -Result $policyResult ` -ExamplePath $Example.RelativePath ` -PolicyName $policyRun.Name $evaluated += $parsed.Evaluated foreach ($issue in $parsed.Issues) { $issues.Add($issue) } } } catch { $primaryError = $_ } try { Invoke-AvmScriptHook ` -HookPath (Join-Path $Example.StagedPath 'post.ps1') ` -WorkingDirectory $Example.StagedPath ` -EnvVars $envVars ` -Label ("policy {0} post.ps1" -f $Example.Name) $Example.CleanupCompleted = $true } catch { if ($null -eq $primaryError) { throw } $primaryError.Exception.Data['AvmPolicyPostError'] = $_ Write-AvmLog ` -Level Warning ` -File (Join-Path $Example.RelativePath 'post.ps1') ` -Message ("Policy post hook also failed ({0}); preserving the primary error and attaching the post error as AvmPolicyPostError." -f $_.Exception.GetType().Name) } if ($null -ne $primaryError) { throw $primaryError } return [pscustomobject]@{ Evaluated = $evaluated Issues = $issues.ToArray() } } function Get-AvmConftestOverrideWarning { [CmdletBinding()] [OutputType([object[]])] param( [Parameter(Mandatory)] [string] $Root, [Parameter(Mandatory)] [string[]] $ExamplePath ) $rootFull = (Resolve-Path -LiteralPath $Root).ProviderPath $warnings = [System.Collections.Generic.List[object]]::new() $seen = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) foreach ($example in $ExamplePath) { $exceptionsPath = Join-Path $example 'exceptions' if (-not (Test-Path -LiteralPath $exceptionsPath -PathType Container)) { continue } $exceptionFiles = @( Get-ChildItem ` -LiteralPath $exceptionsPath ` -Filter '*.rego' ` -File ` -Recurse ` -ErrorAction SilentlyContinue | Sort-Object FullName ) foreach ($exceptionFile in $exceptionFiles) { $file = [System.IO.Path]::GetRelativePath($rootFull, $exceptionFile.FullName).Replace('\', '/') $text = [System.IO.File]::ReadAllText($exceptionFile.FullName) $rules = @( @( foreach ($exceptionMatch in [regex]::Matches($text, '(?ms)\bexception\s+contains\s+rules\s+if\s*\{(?<block>[^{}]*)\}')) { foreach ($ruleListMatch in [regex]::Matches($exceptionMatch.Groups['block'].Value, '(?ms)\brules\s*(?::=|=)\s*\[(?<body>.*?)\]')) { foreach ($ruleMatch in [regex]::Matches($ruleListMatch.Groups['body'].Value, '["''](?<rule>[^"'']+)["'']')) { [string]$ruleMatch.Groups['rule'].Value } } } ) | Select-Object -Unique ) if ($rules.Count -gt 0) { foreach ($rule in $rules) { $key = "$file`0$rule" if (-not $seen.Add($key)) { continue } $warnings.Add([pscustomobject][ordered]@{ File = $file Rule = $rule Message = ("Conftest override exempts rule '{0}'." -f $rule) }) } } elseif ($text -cmatch '\bexception\s+contains\s+rules\s+if\b') { $key = "$file`0" if ($seen.Add($key)) { $warnings.Add([pscustomobject][ordered]@{ File = $file Rule = '' Message = 'Conftest override file found, but no exempted rules could be parsed.' }) } } } } return $warnings.ToArray() } function Invoke-AvmTerraformCheckPolicy { <# .SYNOPSIS Evaluate Terraform examples against the pinned APRL and AVMSEC policies. .DESCRIPTION Implements the legacy AVM pr-check policy lifecycle without mutating the repository. The module is copied beneath the AVM cache, then every direct examples/* directory is evaluated independently with bounded parallelism: - examples carrying .e2eignore are skipped - pre.ps1 runs when present; pre.sh is rejected with migration guidance - .env is loaded into Terraform and Conftest subprocesses - terraform init, plan, and show produce a plan-JSON input - APRL and AVMSEC run separately with all namespaces enabled - the pinned AVMSEC exemptions and that example's local exceptions/ directory are included in both evaluations - post.ps1 runs after the example; post.sh is rejected likewise The staging directory is deliberately beneath the policy bundle cache. Conftest strips the drive letter from --policy paths on Windows; keeping the working tree and bundles on one volume preserves resolution. If any example's post hook fails or cleanup is interrupted, the staging tree is retained in place for recovery. Diagnostics identify its path without printing state, plans, environment values, or hook errors. Conftest output is captured as JSON rather than streamed. The legacy command used --quiet; omitting that switch here has the same user-visible silence while retaining success records needed for the Evaluated count. .PARAMETER Context Terraform module context produced by Get-AvmModuleContext. .PARAMETER AllowPathFallback Allow Terraform and Conftest to resolve from PATH. .PARAMETER ThrottleLimit Maximum number of independent examples to evaluate at once. Defaults to one for direct engine calls. .OUTPUTS A Terraform engine result with Status, Evaluated, and Issues. #> [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory)] $Context, [switch] $AllowPathFallback, [ValidateRange(1, 32)] [int] $ThrottleLimit = 1 ) Set-StrictMode -Version 3.0 $ErrorActionPreference = 'Stop' if ($Context.Ecosystem -ne 'terraform') { throw [System.ArgumentException]::new( "Invoke-AvmTerraformCheckPolicy requires a terraform context (got Ecosystem='$($Context.Ecosystem)').") } $conftest = Resolve-AvmTool -Name 'conftest' -ModuleRoot $Context.Root -AllowPathFallback:$AllowPathFallback $terraform = Resolve-AvmTool -Name 'terraform' -ModuleRoot $Context.Root -AllowPathFallback:$AllowPathFallback $aprlAsset = Resolve-AvmPolicyBundle -Name 'avm-policy-aprl' $avmsecAsset = Resolve-AvmPolicyBundle -Name 'avm-policy-avmsec' $defaultExceptionSource = Join-Path $avmsecAsset.Path 'avm_exceptions.rego.bak' if (-not (Test-Path -LiteralPath $defaultExceptionSource -PathType Leaf)) { throw [AvmConfigurationException]::new( "The pinned AVMSEC bundle does not contain the default exemption policy: '$defaultExceptionSource'.") } $examplesRoot = Join-Path $Context.Root 'examples' $examplePaths = @() if (Test-Path -LiteralPath $examplesRoot -PathType Container) { $examplePaths = @(Get-ChildItem -LiteralPath $examplesRoot -Directory -ErrorAction Stop | ForEach-Object FullName) [System.Array]::Sort($examplePaths, [System.StringComparer]::Ordinal) } $activeExamples = @($examplePaths | Where-Object { -not (Test-Path -LiteralPath (Join-Path $_ '.e2eignore') -PathType Leaf) }) if ($activeExamples.Count -eq 0) { return [pscustomobject][ordered]@{ Engine = 'terraform' Tool = ('{0}/{1}' -f $conftest.Name, $conftest.Version) ToolPath = $conftest.Path ToolSource = $conftest.Source Status = 'skipped' Evaluated = 0 Issues = @() } } foreach ($warning in (Get-AvmConftestOverrideWarning -Root $Context.Root -ExamplePath $activeExamples)) { Write-AvmLog ` -Message $warning.Message ` -Level Warning ` -File $warning.File } $shellHooks = [System.Collections.Generic.List[string]]::new() foreach ($sourceExample in $activeExamples) { $exampleName = Split-Path -Path $sourceExample -Leaf foreach ($hookName in @('pre.sh', 'post.sh')) { if (Test-Path -LiteralPath (Join-Path $sourceExample $hookName) -PathType Leaf) { $shellHooks.Add(('examples/{0}/{1}' -f $exampleName, $hookName)) } } } if ($shellHooks.Count -gt 0) { throw [AvmConfigurationException]::new( ("The terraform policy engine runs PowerShell hooks only. Refactor these shell hooks to '.ps1': {0}" -f ($shellHooks -join ', '))) } $stageParent = Join-Path (Get-AvmFolder -Kind Cache) 'policy-stage' $stageRoot = Join-Path $stageParent ('avm-policy-' + [guid]::NewGuid().ToString('N')) $issues = [System.Collections.Generic.List[object]]::new() $evaluated = 0 $streamOutput = Test-AvmVerboseEnabled $effectiveThrottle = if ($streamOutput) { 1 } else { $ThrottleLimit } $examples = [System.Collections.Generic.List[object]]::new() $policyError = $null try { $defaultExceptions = Join-Path ` -Path $stageRoot ` -ChildPath 'policy' ` -AdditionalChildPath 'default_exceptions' $null = New-Item -ItemType Directory -Path $defaultExceptions -Force -ErrorAction Stop Copy-Item ` -LiteralPath $defaultExceptionSource ` -Destination (Join-Path $defaultExceptions 'avm_exceptions.rego') ` -Force ` -ErrorAction Stop for ($exampleIndex = 0; $exampleIndex -lt $activeExamples.Count; $exampleIndex++) { $sourceExample = $activeExamples[$exampleIndex] $relativeExample = [System.IO.Path]::GetRelativePath($Context.Root, $sourceExample) $caseRoot = Join-Path $stageRoot ([string]$exampleIndex) $moduleStage = Join-Path $caseRoot 'module' Copy-AvmTerraformModuleTree ` -SourceRoot $Context.Root ` -DestinationRoot $moduleStage ` -IncludeDependencyLocks $stagedExample = Join-Path $moduleStage $relativeExample $null = Copy-AvmTerraformModuleCache ` -SourceWorkingDirectory $sourceExample ` -DestinationWorkingDirectory $stagedExample ` -DestinationDataDirectory (Join-Path $caseRoot 'data') $exampleName = Split-Path -Path $sourceExample -Leaf Write-AvmLog ` -Level Info ` -Message ("policy: example {0}/{1} = {2}" -f ($exampleIndex + 1), $activeExamples.Count, $exampleName) | Out-Null $examples.Add([pscustomobject]@{ Name = $exampleName RelativePath = $relativeExample StagedPath = $stagedExample StageRoot = $caseRoot CleanupStarted = $false CleanupCompleted = $false }) } Write-AvmLog ` -Level Verbose ` -Message ("policy: processing examples with {0} worker(s)" -f $effectiveThrottle) | Out-Null $options = [pscustomobject]@{ TerraformPath = $terraform.Path ConftestPath = $conftest.Path AprlPath = $aprlAsset.Path AvmsecPath = $avmsecAsset.Path DefaultExceptions = $defaultExceptions } $exampleResults = @( Invoke-AvmParallel ` -InputObject $examples.ToArray() ` -FunctionName 'Invoke-AvmTerraformPolicyExample' ` -Argument $options ` -ThrottleLimit $effectiveThrottle ) foreach ($exampleResult in $exampleResults) { $evaluated += $exampleResult.Evaluated foreach ($issue in $exampleResult.Issues) { $issues.Add($issue) } } } catch { $policyError = $_ throw } finally { if (Test-Path -LiteralPath $stageRoot) { if (@($examples | Where-Object { $_.CleanupStarted -and -not $_.CleanupCompleted }).Count -gt 0) { if ($null -ne $policyError) { $policyError.Exception.Data['AvmPolicyStagePath'] = $stageRoot } Write-AvmLog ` -Level Warning ` -Message ("Policy cleanup is incomplete. Recovery staging is retained at '{0}'. It may contain sensitive state, plans, and environment files; do not upload it. Recover resources before manually removing this directory." -f $stageRoot) } else { try { Remove-Item ` -LiteralPath $stageRoot ` -Recurse ` -Force ` -ErrorAction Stop ` -ProgressAction SilentlyContinue } catch { if ($null -eq $policyError) { $_.Exception.Data['AvmPolicyStagePath'] = $stageRoot Write-AvmLog ` -Level Warning ` -Message ("Policy staging removal failed ({0}). Remaining staging is at '{1}'; do not upload it." -f $_.Exception.GetType().Name, $stageRoot) throw } $policyError.Exception.Data['AvmPolicyStageCleanupError'] = $_ $policyError.Exception.Data['AvmPolicyStagePath'] = $stageRoot Write-AvmLog ` -Level Warning ` -Message ("Policy staging removal also failed ({0}); preserving the primary error. Remaining staging is at '{1}'; do not upload it." -f $_.Exception.GetType().Name, $stageRoot) } } } } $status = if (@($issues | Where-Object { $_.Severity -eq 'error' }).Count -gt 0) { 'fail' } else { 'pass' } return [pscustomobject][ordered]@{ Engine = 'terraform' Tool = ('{0}/{1}' -f $conftest.Name, $conftest.Version) ToolPath = $conftest.Path ToolSource = $conftest.Source Status = $status Evaluated = $evaluated Issues = $issues.ToArray() } } function ConvertFrom-AvmPolicyResult { [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory)] $Result, [Parameter(Mandatory)] [string] $ExamplePath, [Parameter(Mandatory)] [string] $PolicyName ) if ($Result.ExitCode -notin @(0, 1)) { $summary = "conftest $PolicyName exited with code $($Result.ExitCode)." $message = Add-AvmProcessFailureDetail ` -Message $summary ` -StdOut $Result.StdOut ` -StdErr $Result.StdErr if ($message -ceq $summary) { $message += [Environment]::NewLine + ' conftest produced no diagnostic.' } throw [AvmProcessException]::new( $message) } $payload = if ($Result.StdOut) { $Result.StdOut.Trim() } else { '' } if ($Result.ExitCode -eq 1 -and [string]::IsNullOrWhiteSpace($payload)) { $summary = "conftest $PolicyName exited before evaluating a policy." $message = Add-AvmProcessFailureDetail ` -Message $summary ` -StdOut $Result.StdOut ` -StdErr $Result.StdErr if ($message -ceq $summary) { $message += [Environment]::NewLine + ' conftest produced no result.' } throw [AvmProcessException]::new( $message) } $records = @() if (-not [string]::IsNullOrWhiteSpace($payload)) { try { $records = @($payload | ConvertFrom-Json -ErrorAction Stop) } catch { throw [AvmProcessException]::new( "Could not parse conftest $PolicyName JSON output: $($_.Exception.Message)") } } $issues = [System.Collections.Generic.List[object]]::new() $evaluated = 0 $issueFile = [System.IO.Path]::Combine($ExamplePath, 'tfplan.json').Replace('\', '/') foreach ($record in $records) { if (-not $record) { continue } $namespace = if ($record.PSObject.Properties['namespace']) { [string]$record.namespace } else { $PolicyName.ToLowerInvariant() } if ($record.PSObject.Properties['successes']) { $evaluated += [int]$record.successes } foreach ($bucket in @('failures', 'warnings', 'exceptions')) { if ($record.PSObject.Properties[$bucket] -and $record.$bucket) { $evaluated += @($record.$bucket).Count } } foreach ($bucket in @( [pscustomobject]@{ Name = 'failures'; Severity = 'error' } [pscustomobject]@{ Name = 'warnings'; Severity = 'warning' } )) { if (-not $record.PSObject.Properties[$bucket.Name] -or -not $record.($bucket.Name)) { continue } foreach ($finding in @($record.($bucket.Name))) { $message = if ($finding.PSObject.Properties['msg']) { [string]$finding.msg } else { '' } $issues.Add([pscustomobject][ordered]@{ File = $issueFile Line = 0 Column = 0 Severity = $bucket.Severity Code = $namespace Message = $message }) } } } return [pscustomobject][ordered]@{ Evaluated = $evaluated Issues = $issues.ToArray() } } # SIG # Begin signature block # MIInQQYJKoZIhvcNAQcCoIInMjCCJy4CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAMHAcQr9XmEQUD # hQ5+Al95qkqA/I5trqZoATyLPaqb9qCCDLowggX1MIID3aADAgECAhMzAAACHU0Z # yE7XD1dIAAAAAAIdMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAlVTMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBD # b2RlIFNpZ25pbmcgUENBIDIwMjQwHhcNMjYwNDE2MTg1OTQzWhcNMjcwNDE1MTg1 # OTQzWjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYD # VQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IB # DwAwggEKAoIBAQDQvewXxx9gZZFC6Ys1WBay8BJ8kGA4JQnH5CMafqOASlTpK9H8 # o5ZXTXt0caVQTNMUPt445wXYD+dFtaKWTwDn1I52oUSrC9vJin1Gsqt+zyKJL5Dg # 3eQXbQNR61DmMy20GLTIO3SFed9Rfi/ophgCLGFLDR3r0KvHjwMb/jYWS0celV/4 # Lz27LfAekm8v9E5IXaeiXbAUYZKK090n4CVl3JBtbN+9DtI9SNu/yjvozW52/u7R # X/Ttpa/KDlpuokZ+Zcbvmtd9ur9gFLvZzh41o9MsE/clQtdaFWGvuo6Jua/ntpgk # ey3E5/vBFe+MJPG6phdnuo6r57ZudCudiI1bAgMBAAGjggGbMIIBlzAOBgNVHQ8B # Af8EBAMCB4AwHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0O # BBYEFH6QuMwqcPG0hQlQ6c5jCtTTLrVeMEUGA1UdEQQ+MDykOjA4MR4wHAYDVQQL # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xFjAUBgNVBAUTDTIzMDAxMis1MDc1NTkw # HwYDVR0jBBgwFoAUf1k/VCHarU/vBeXmo9ctBpQSCDEwYAYDVR0fBFkwVzBVoFOg # UYZPaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0 # JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNybDBtBggrBgEFBQcBAQRh # MF8wXQYIKwYBBQUHMAKGUWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv # Y2VydHMvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNy # dDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQBKTbYOjzwTG/DXGaz9 # s6+fQeaTtDcFmMY+5UyVFCyj7Pv+5i37qfX8lSL/tBIfYQfWsMuBQlfZurJD6r4H # VJ2CeH+1fgiq8dcHdVKoZ3Sa2qXoX3cq9iS8cVb06B7+5/XJ7I0OxHH9fDsvJ3T3 # w5V/ZtAIFmLrl+P0CtG+92uzRsn0nTbdFjOkLMLWPLAU3THohKRlSEMgFJpPkm5n # 5UAZ35xX6FWCrDLsSKb555bTifwa8mJBwdlof0bmfYidH+dxZ1FdDxvLnNl9zeKs # A4kejaaIqqIPguhwAti5Ql7BlTNoJNwxCvBmqW2MQLnCkYN/VVUsR3V2x/rcTNzo # Bf/Z/SpROvdaA2ZOOd1uioXJt3tdLQ7vHpqpib0KfWr/FWXW10q38VxfCnRQBqzb # SuztR7nEMuzX7Ck+B/XaPDXd1qh72+QYyB0Z2VzWmO9zsnb9Uq/dwu8LGeQqnyu6 # 7SDGACvnXii2fb9+US492VTnXSnFKyqwgzUyFMtZK1/sHYTv6bG4TtQUygQxTN+Z # V+aJIlKO2MqZ7bKrAnOzS9m6NgoTdWOq11bTOZwKlIEV/EhV9SWkDmdpR/hPPT2v # 6TEj4F8PT/zHjRezIU5c/DGlt/VhY/pK0XkJtEyMmmS1BMtjU/rqBZVMIm3dnxQs # /TBByr+Cf8Z1r7aifQVQ+WSqzjCCBr0wggSloAMCAQICEzMAAAA5O7Y3Gb8GHWcA # AAAAADkwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRl # IEF1dGhvcml0eSAyMDExMB4XDTI0MDgwODIwNTQxOFoXDTM2MDMyMjIyMTMwNFow # VzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEo # MCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAyNDCCAiIwDQYJ # KoZIhvcNAQEBBQADggIPADCCAgoCggIBANgBnB7jOMeqlRYHNa265v4IY9fH8TKh # emHfPINe1gpLaV3dhg324WwH06LcHbpnsBukCDNitryo0dtS/EW6I/yEL/bLSY8h # KpbfQuWusBPr9qazYcDxCW/qnjb5JsI1s8bNOg3bVATvQVL4tcf03aTycsz8QeCd # M0l/yHRObJ9QqazM1r6VPEOJ7LL+uEEb73w6QCuhs89a1uv1zerOYMnsneRRwCbp # yW11IcggU0cRKDDq1pjVJzIbIF6+oiXXbReOsgeI8zu1FyQfK0fVkaya8SmVHQ/t # Of23mZ4W9k0Ri22QW9p3UgSC5OUDktKxxcCmGL6tXLfOGSWHIIV4YrTJTT6PNty5 # REojHJuZHArkF9VnHTERWoTjAzfI3kP+5b4alUdhgAZ7ttOu1bVnXfHaqPYl2rPs # 20ji03LOVWsh/radgE17es5hL+t6lV0eVHrVhsssROWJuz2MXMCt7iw7lFPG9LXK # Gjsmonn2gotGdHIuEg5JnJMJVmixd5LRlkmgYRZKzhxSCwyoGIq0PhaA7Y+VPct5 # pCHkijcIIDm0nlkK+0KyepolcqGm0T/GYQRMhHJlGOOmVQop36wUVUYklUy++vDW # eEgEo4s7hxN6mIbf2MSIQ/iIfMZgJxC69oukMUXCrOC3SkE/xIkgpfl22MM1itkZ # 35nNXkMolU1lAgMBAAGjggFOMIIBSjAOBgNVHQ8BAf8EBAMCAYYwEAYJKwYBBAGC # NxUBBAMCAQAwHQYDVR0OBBYEFH9ZP1Qh2q1P7wXl5qPXLQaUEggxMBkGCSsGAQQB # gjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU # ci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2Ny # bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0MjAx # MV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRSMFAwTgYIKwYBBQUHMAKGQmh0 # dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0MjAx # MV8yMDExXzAzXzIyLmNydDANBgkqhkiG9w0BAQwFAAOCAgEAFJQfOChP7onn6fLI # MKrSlN1WYKwDFgAddymOUO3FrM8d7B/W/iQ6DxXsDn7D5W4wMwYeLystcEqfkjz4 # NURRgazyMu5yRzQh4LqjA4tStTcJh1opExo7nn5PuPBYnbu0+THSuVHTe0VTTPVh # ily/piFrDo3axQ9P4C+Ol5yet+2gTfekICS5xS+cYfSIvgn0JksVBVMYVI5QFu/q # hnLhsEFEUzG8fvv0hjgkO+lkpV9ty6GkN4vdnd7ya6Q6aR9y34aiM1qmxaxBi6OU # nyNl6fkuun/diTFnYDLTppOkr/mg5WSfCiDVMNCxtj4wPKC5OmHm1DQIt/MNokbb # H3UGsFP1QbzsLocuSqLCvH09Io3fDPTmscR9Y75G4qX7RTX8AdBPo0I6OEojf39z # uFZt0qOHm65YWQE69cZM2ueE1MB05dNNgHK9gTE7zKvK/fg8B2qjW88MT/WF5V5u # vZGtqa9FSL2RazArA+rDPuf6JGYz4HpgMZHB4S6szWSKYBv0VisCzfxgeU+dquXW # 9bd0auYlOB58DPcOYKdc3Se94g+xL4pcEhbB54JOgAkwYTu/9dLeH2pDqeJZAABV # DWRQCaXfO5LgyKwKCLYXpigrZYCjUSBcr+Ve8PFWMhVTQl0v4q8J/AUmQN5W4n10 # 1cY2L4A7GTQG1h32HHAvfQESWP0xghndMIIZ2QIBATBuMFcxCzAJBgNVBAYTAlVT # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jv # c29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMjQCEzMAAAIdTRnITtcPV0gAAAAAAh0w # DQYJYIZIAWUDBAIBBQCggZAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwLwYJ # KoZIhvcNAQkEMSIEIGe8EoaxUTiqlAFaKgef32Ct3xl5Nwgj8anNAO6NxVWFMEIG # CisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEBBQAEggEAsVgbvksH642FHz2Q # yT5GwV8y3AoniuGmXVK6Utf6LeZFmop/NjDUtljcVs3ClPH++B+bM5QnAvzOMgHK # uUPHBolJ/kGBW397VjzdRqkgDV6MYRNk8A/xBrtATYWEbh265RzqSGeBvMnlr7y2 # CQP0rFlloy/MF0Sw9Kzm2lfzlVV2Yl4Hv3aNKbZzPixAA82yo8PrcsOxZlJGGScM # m0HcBZ996ro27XYTnx3lpvFJB0JdogyLzEKb3FDpj/eqFTf867L2Rj9rVTu7h2TD # dV/TjfMqS4CnNnUm7gOd2CbUt64kjufI8QezkibplHU4xpG/ASrOdcJEYy55L/v4 # 8LvwL6GCF60wghepBgorBgEEAYI3AwMBMYIXmTCCF5UGCSqGSIb3DQEHAqCCF4Yw # gheCAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsqhkiG9w0BCRABBKCCAUkEggFF # MIIBQQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUABCBjJ4z5oug2Jutd # fpKIBlzYUKqS4e6QPjjVPzQ4QKva9AIGaq5iqxdxGBMyMDI2MTAxNTE5MDMyMS44 # MDFaMASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu # Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv # cmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExp # bWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo0QzFBLTA1RTAtRDk0NzEl # MCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCEfswggcoMIIF # EKADAgECAhMzAAACGCXZkgXi5+XkAAEAAAIYMA0GCSqGSIb3DQEBCwUAMHwxCzAJ # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jv # c29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI1MDgxNDE4NDgyNVoXDTI2MTEx # MzE4NDgyNVowgdMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw # DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x # LTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEn # MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjRDMUEtMDVFMC1EOTQ3MSUwIwYDVQQD # ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEF # AAOCAg8AMIICCgKCAgEAsdzo6uuQJqAfxLnvEBfIvj6knK+p6bnMXEFZ/QjPOFyw # lcjDfzI8Dg1nzDlxm7/pqbvjWhyvazKmFyO6qbPwClfRnI57h5OCixgpOOCGJJQI # ZSTiMgui3B8DPiFtJPcfzRt3FsnxjLXwBIjGgnjGfmQl7zejA1WoYL/qBmQhw/FD # FTWebxfo4m0RCCOxf2qwj31aOjc2aYUePtLMXHsXKPFH0tp5SKIF/9tJxRSg0NYE # vQqVilje8aQkPd3qzAux2Mc5HMSK4NMTtVVCYAWDUZ4p+6iDI9t5BNCBIsf5ooFN # UWtxCqnpFYiLYkHfFfxhVUBZ8LGGxYsA36snD65s2Hf4t86k0e8WelH/usfhYqOM # 3z2yaI8rg08631IkwqUzyQoEPqMsHgBem1xpmOGSIUnVvTsAv+lmECL2RqrcOZlZ # ax8K0aiij8h6UkWBN2IA/ikackTSGVRBQmWWZuLFWV/T4xuNzscC0X7xo4fetgps # qaEA0jY/QevkTvLv4OlNN9eOL8LNh7Vm0R65P7oabOQDqtUFAwCgjgPJ0iV/jQCa # MAcO3SYpG5wSAYiJkk4XLjNSlNxU2Idjs1sORhl7s7LC6hOb7bVAHVwON74GxfFN # iEIA6BfudANjpQJ0nUc/ppEXpT4pgDBHsYtV8OyKSjKsIxOdFR7fIJIjDc8DvUkC # AwEAAaOCAUkwggFFMB0GA1UdDgQWBBQkLqHEXDobY7dHuoQCBa4sX7aL0TAfBgNV # HSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5o # dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBU # aW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwG # CCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRz # L01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNV # HRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIH # gDANBgkqhkiG9w0BAQsFAAOCAgEAnkjRhjwPgdoIpvt4YioT/j0LWuBxF3ARBKXD # ENggraKvC0oRPwbjAmsXnPEmtuo5MD8uJ9Xw9eYrxqqkK4DF9snZMrHMfooxCa++ # 1irLz8YoozC4tci+a4N37Sbke1pt1xs9qZtvkPgZGWn5BcwVfmAwSZLHi2CuZ06Y # 0/X+t6fNBnrbMVovNaDX4WPdyI9GEzxfIggDsck2Ipo4VXL/Arcz7p2F7bEZGRuy # xjgMC+woCkDJaH/yk/wcZpAsixe4POdN0DW6Zb35O3Dg3+a6prANMc3WIdvfKDl7 # 5P0aqcQbQAR7b0f4gH4NMkUct0Wm4GN5KhsE1YK7V/wAqDKmK4jx3zLz3a8Hsxa9 # HB3GyitlmC5sDhOl4QTGN5kRi6oCoV4hK+kIFgnkWjHhSRNomz36QnbCSG/BHLEm # 2GRU9u3/I4zUd9E1AC97IJEGfwb+0NWb3QEcrkypdGdWwl0LEObhrQR9B1V7+edc # yNmsX0p2BX0rFpd1PkXJSbxf8IcEiw/bkNgagZE+VlDtxXeruLdo5k3lGOv7rPYu # OEaoZYxDvZtpHP9P36wmW4INjR6NInn2UM+krP/xeLnRbDBkm9RslnoDhVraliKD # H62BxhcgL9tiRgOHlcI0wqvVWLdv8yW8rxkawOlhCRqT3EKECW8ktUAPwNbBULkT # +oWcvBcwggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZAAAAAAAVMA0GCSqGSIb3 # DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIw # MAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAx # MDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1l # LVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA # 5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4XYDP/ # XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTzxXb1 # hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7uhp7 # M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928jaTjkY+yOSxRnOlwaQ3K # Ni1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3tpK56KTesy+uDRedGbsoy # 1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGaRnXNxF80 # 3RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fzpk03dJQc # NIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9ahha # YQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5UPkL # iWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReTwDwV # 2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZMBIG # CSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8RjUp # zxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAEVTBT # MFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jv # c29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYI # KwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGG # MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186a # GMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3Br # aS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsG # AQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcN # AQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9MTO1 # OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2LpypglYA # A7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OOPcbz # aN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8DJ6L # GYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmRsqlb30mjdAy87JGA0j3m # Sj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8x1RtnWN0 # SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjcZxko # JLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq77EFm # PWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJC482 # 2rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328y+l7 # vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIDVjCC # Aj4CAQEwggEBoYHZpIHWMIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu # Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv # cmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExp # bWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo0QzFBLTA1RTAtRDk0NzEl # MCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsO # AwIaAxUAnWtGrXWiuNE8QrKfm4CtGr57z+mggYMwgYCkfjB8MQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGlt # ZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsFAAIFAO57JTkwIhgPMjAyNjEw # MTUxMDExMDVaGA8yMDI2MTAxNjEwMTEwNVowdDA6BgorBgEEAYRZCgQBMSwwKjAK # AgUA7nslOQIBADAHAgEAAgIFzDAHAgEAAgIUQDAKAgUA7nx2uQIBADA2BgorBgEE # AYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYag # MA0GCSqGSIb3DQEBCwUAA4IBAQBShR7QhG8wyLs/aXenY3icx0+iutQ1yPc//wJ6 # 3ER8T2hx1LQdUW2p8/iYHOdAROkaN8E+lG8RU9RVSP9+3jdXb6tOvamBuNMm2l3e # uDKd+thZti256uzDqVlrAYMZmY1Tvsgn7LQGKrIu55bLy9N/RpKfQq+g2Q+g+mvy # RwBM8e501kcBf8Sx6D2E6x4HryqooEziDVwjOaB6Z1V7hMQPwR0ZxyF9et26Csx1 # /oZuhkerLwnVj0OjITYw0JpgXMGXEww4sfoP8DLoz+WIJWdAppQ4HJpmKBo93Ij/ # ur4ClszU7YtUs53un8qWuozDlk+tGR3yDotFhQiV/IA/C3WgMYIEDTCCBAkCAQEw # gZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT # B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UE # AxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAIYJdmSBeLn5eQA # AQAAAhgwDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0B # CRABBDAvBgkqhkiG9w0BCQQxIgQg0aUfxkmPJt9gCtwCPpVfdd2O4HkTUk1Zh8Iz # GKhjEhUwgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCCZE9yJuOTItIwWaES6 # lzGKK1XcSoz1ynRzaOVzx9eFajCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w # IFBDQSAyMDEwAhMzAAACGCXZkgXi5+XkAAEAAAIYMCIEIKEuKyoM8AL1FqzedI/2 # re/iCNW7j+n00r49pH98tIygMA0GCSqGSIb3DQEBCwUABIICAI9gAg2ngFpgPpm3 # h5LbsWzIxVnWYR40n7KG6EZs+qjxZ55iHSSRhjc8rKxECHNN1V9MJNlMLcIVnBbe # rGKLDk3rDL1UcWsYeVYGoTB9OSGwOUW9drxX0juxSIVhfFXa2TV1jAgmFIJdssfZ # z1SIDIFTpa7m9B7GsVYROzCjF8iiVyTuG0XS51wYcswTz28+wFg2DFdVtF1o/FT6 # Ae08rApnBGwjfyjI8Do3KAWQiVozCsdcFNDxqDP0+FA7KdpLEHthOjupDF84sTQk # rQkMmfQA3RYCQK576JF19M9fWCP+n8Be1VZi0+5N4MRHdH4eJHKFdtSlafKzixHk # r7QX6IvOjXMaqUiCT4br11hUmq3PRcjrGbUUxZcokztQd4emXj+yHPT72DsixHoN # 3DqdODcAXQqYpRWoqOa0Cu0soHN76K7TOnDdkeXdtEa8jVKzRvNKQzHcElW/KkbV # xSkRgwPbSYul3q0b1kBawlEI41WedrtAulaZ+ptC5LARN1Xidlwt1tD1AQTFRr07 # Ta9vgcW9zloiQE74r360oQfyvjqpTdXhxAx86akmvej8R09z8U4c0/HmR1u1103C # Zlz6IgXyjnY/iP0ff9R4Wh4rKVZzOlg2sXkwCzRXPQxfS0j6Zw5M08QY6fl/MSve # Kss5WX4gTZJMCv6SGiC6YBQNwzLW # SIG # End signature block |