Private/Deploy-Accelerator-Helpers/Request-ALZConfigurationValue.ps1
|
function Request-ALZConfigurationValue { <# .SYNOPSIS Parses configuration files and prompts the user for input values interactively. .DESCRIPTION This function reads the inputs.yaml file, loads the schema for descriptions and help links, and prompts the user for values. It prompts for all inputs in inputs.yaml. .PARAMETER ConfigFolderPath The path to the folder containing the configuration files. .PARAMETER IacType The Infrastructure as Code type (terraform or bicep). .PARAMETER VersionControl The version control system (github, azure-devops, or local). .PARAMETER AzureContextOutputDirectory The output directory to pass to Get-AzureContext for caching Azure context data. .PARAMETER AzureContextClearCache When set, clears the cached Azure context data before fetching. .PARAMETER SensitiveOnly When set, only prompts for sensitive inputs that are not already set (via environment variables or non-empty config values). .OUTPUTS Returns $true if configuration was updated, $false otherwise. #> [CmdletBinding(SupportsShouldProcess = $true)] param( [Parameter(Mandatory = $true)] [string] $ConfigFolderPath, [Parameter(Mandatory = $true)] [string] $IacType, [Parameter(Mandatory = $true)] [string] $VersionControl, [Parameter(Mandatory = $false)] [string] $AzureContextOutputDirectory = "", [Parameter(Mandatory = $false)] [switch] $AzureContextClearCache, [Parameter(Mandatory = $false)] [switch] $SensitiveOnly ) # Helper function to get a property from schema info safely function Get-SchemaProperty { param($SchemaInfo, $PropertyName, $Default = $null) if ($null -ne $SchemaInfo -and $SchemaInfo.PSObject.Properties.Name -contains $PropertyName) { return $SchemaInfo.$PropertyName } return $Default } # Helper function to prompt for a single input value function Read-InputValue { param( $Key, $CurrentValue, $SchemaInfo, $Indent = "", $DefaultDescription = "No description available", $AzureContext ) # Use pre-fetched Azure context data from parent scope $description = Get-SchemaProperty -SchemaInfo $SchemaInfo -PropertyName "description" -Default $DefaultDescription $helpLink = Get-SchemaProperty -SchemaInfo $SchemaInfo -PropertyName "helpLink" $isSensitive = Get-SchemaProperty -SchemaInfo $SchemaInfo -PropertyName "sensitive" -Default $false $schemaType = Get-SchemaProperty -SchemaInfo $SchemaInfo -PropertyName "type" -Default "string" $isRequired = Get-SchemaProperty -SchemaInfo $SchemaInfo -PropertyName "required" -Default $false $source = Get-SchemaProperty -SchemaInfo $SchemaInfo -PropertyName "source" # For sensitive inputs, check if value is set via environment variable $envVarValue = $null if ($isSensitive) { $envVarName = "TF_VAR_$Key" $envVarValue = [System.Environment]::GetEnvironmentVariable($envVarName) if (-not [string]::IsNullOrWhiteSpace($envVarValue)) { $CurrentValue = $envVarValue } } # Check if the current value is an array $isArray = $schemaType -eq "array" -or $CurrentValue -is [System.Collections.IList] # Check if the current value is a placeholder (surrounded by angle brackets) $isPlaceholder = $false $hasPlaceholderItems = $false if ($isArray) { # Check if array contains placeholder items if ($null -ne $CurrentValue -and $CurrentValue.Count -gt 0) { foreach ($item in $CurrentValue) { if ($item -is [string] -and $item -match '^\s*<.*>\s*$') { $hasPlaceholderItems = $true break } } } } elseif ($CurrentValue -is [string] -and $CurrentValue -match '^\s*<.*>\s*$') { $isPlaceholder = $true } # Determine effective default (don't use placeholders as defaults) $effectiveDefault = if ($isPlaceholder) { "" } elseif ($isArray -and $hasPlaceholderItems) { @() } else { $CurrentValue } # Build base parameters for Read-MenuSelection $menuParams = @{ Title = $Key HelpText = @($description, $helpLink) Options = @() DefaultValue = $effectiveDefault AllowManualEntry = $true ManualEntryPrompt = "Enter value (press enter to accept default)" Type = $schemaType IsRequired = $isRequired RequiredMessage = "This field is required. Please enter a value." IsSensitive = $isSensitive } # Customize parameters based on input type if ($isArray) { $menuParams.HelpText = @($description, $helpLink, "Format: Comma-separated list of values") $menuParams.ManualEntryPrompt = "Enter values (comma-separated)" $menuParams.RequiredMessage = "This field is required. Please enter values." } elseif ($source -eq "subscription") { $menuParams.OptionsTitle = "Available subscriptions:" $menuParams.Options = $AzureContext.Subscriptions $menuParams.ManualEntryPrompt = "Enter subscription ID" $menuParams.RequiredMessage = "This field is required. Please select a subscription." $menuParams.EmptyMessage = "No subscriptions found in Azure context." } elseif ($source -eq "managementGroup") { $menuParams.OptionsTitle = "Available management groups:" $menuParams.Options = $AzureContext.ManagementGroups $menuParams.ManualEntryPrompt = "Enter management group ID" $menuParams.RequiredMessage = "This field is required. Please select a management group." $menuParams.EmptyMessage = "No management groups found in Azure context." } elseif ($source -eq "azureRegion") { $menuParams.OptionsTitle = "Available regions (AZ = Availability Zone support):" $menuParams.Options = $AzureContext.Regions $menuParams.ManualEntryPrompt = "Enter region name (e.g., uksouth, eastus)" $menuParams.RequiredMessage = "This field is required. Please select a region." $menuParams.EmptyMessage = "No regions found in Azure context." } elseif ($schemaType -eq "boolean") { $menuParams.ManualEntryPrompt = "Enter value (true/false) (press enter to accept default)" $menuParams.DefaultValue = $effectiveDefault.ToString().ToLower() } $newValue = Read-MenuSelection @menuParams # Return value along with sensitivity info return @{ Value = $newValue IsSensitive = $isSensitive } } if ($PSCmdlet.ShouldProcess("Configuration files", "prompt for input values")) { $AzureContext = $null # Fetch Azure context once upfront if not in SensitiveOnly mode if (-not $SensitiveOnly.IsPresent) { if (-not [string]::IsNullOrWhiteSpace($AzureContextOutputDirectory)) { $AzureContext = Get-AzureContext -OutputDirectory $AzureContextOutputDirectory -ClearCache:$AzureContextClearCache.IsPresent } else { $AzureContext = Get-AzureContext -ClearCache:$AzureContextClearCache.IsPresent } } Write-Verbose (ConvertTo-Json $AzureContext) # Load the schema file $schemaPath = Join-Path $PSScriptRoot "AcceleratorInputSchema.json" if (-not (Test-Path $schemaPath)) { Write-Warning "Schema file not found at $schemaPath. Proceeding without descriptions." $schema = $null } else { $schema = Get-Content -Path $schemaPath -Raw | ConvertFrom-Json } # Define the configuration files to process $inputsYamlPath = Join-Path $ConfigFolderPath "inputs.yaml" $configUpdated = $false # Process inputs.yaml - prompt for ALL inputs if (Test-Path $inputsYamlPath) { Write-ToConsoleLog "=== Bootstrap Configuration (inputs.yaml) ===" Write-ToConsoleLog "For more information, see: https://aka.ms/alz/acc/phase0" # Read the raw content to preserve comments and ordering $inputsYamlContent = Get-Content -Path $inputsYamlPath -Raw $inputsConfig = $inputsYamlContent | ConvertFrom-Yaml -Ordered $inputsUpdated = $false $sensitiveEnvVars = @{} # Get the appropriate schema sections based on version control $bootstrapSchema = $null $vcsSchema = $null if ($null -ne $schema) { $bootstrapSchema = $schema.inputs.bootstrap.properties if ($VersionControl -eq "github") { $vcsSchema = $schema.inputs.github.properties } elseif ($VersionControl -eq "azure-devops") { $vcsSchema = $schema.inputs.azure_devops.properties } elseif ($VersionControl -eq "local") { $vcsSchema = $schema.inputs.local.properties } } # Helper: look up schema info for a key from bootstrap or VCS schema function Get-InputSchemaInfo { param($Key, $BootstrapSchema, $VcsSchema) if ($null -ne $BootstrapSchema -and $BootstrapSchema.PSObject.Properties.Name -contains $Key) { return $BootstrapSchema.$Key } if ($null -ne $VcsSchema -and $VcsSchema.PSObject.Properties.Name -contains $Key) { return $VcsSchema.$Key } return $null } # Helper: format a value for inline YAML output (strongly typed) function Format-YamlInlineValue { param($Value) if ($null -eq $Value) { return "" } if ($Value -is [bool]) { if ($Value) { return "true" } else { return "false" } } if ($Value -is [int] -or $Value -is [long] -or $Value -is [double]) { return $Value.ToString() } if ($Value -is [System.Collections.IList]) { if ($Value.Count -eq 0) { return "[]" } $items = ($Value | ForEach-Object { "`"$_`"" }) -join ", " return "[$items]" } if ($Value -is [System.Collections.IDictionary]) { return "" } return "`"$Value`"" } foreach ($key in @($inputsConfig.Keys)) { $currentValue = $inputsConfig[$key] # Handle nested dictionary objects generically (e.g. subscription_ids) if ($currentValue -is [System.Collections.IDictionary]) { if ($SensitiveOnly.IsPresent) { continue } $parentSchemaInfo = Get-InputSchemaInfo -Key $key -BootstrapSchema $bootstrapSchema -VcsSchema $vcsSchema if ($null -eq $parentSchemaInfo) { continue } $nestedSchema = Get-SchemaProperty -SchemaInfo $parentSchemaInfo -PropertyName "properties" if ($null -eq $nestedSchema) { continue } foreach ($subKey in @($currentValue.Keys)) { $subCurrentValue = $currentValue[$subKey] $subSchemaInfo = $null if ($nestedSchema.PSObject.Properties.Name -contains $subKey) { $subSchemaInfo = $nestedSchema.$subKey } else { continue } $result = Read-InputValue -Key $subKey -CurrentValue $subCurrentValue -SchemaInfo $subSchemaInfo -DefaultDescription "$key - $subKey" -AzureContext $AzureContext $subNewValue = $result.Value if ($subNewValue -ne $subCurrentValue) { $currentValue[$subKey] = [string]$subNewValue $inputsUpdated = $true } } continue } # Look up schema info $schemaInfo = Get-InputSchemaInfo -Key $key -BootstrapSchema $bootstrapSchema -VcsSchema $vcsSchema if ($null -eq $schemaInfo) { continue } # Check if this is a sensitive input $isSensitiveField = Get-SchemaProperty -SchemaInfo $schemaInfo -PropertyName "sensitive" -Default $false $schemaType = Get-SchemaProperty -SchemaInfo $schemaInfo -PropertyName "type" -Default "string" # In SensitiveOnly mode, skip non-sensitive inputs if ($SensitiveOnly.IsPresent -and -not $isSensitiveField) { continue } # In SensitiveOnly mode, check if sensitive value is already set if ($SensitiveOnly.IsPresent -and $isSensitiveField) { $envVarName = "TF_VAR_$key" $envVarValue = [System.Environment]::GetEnvironmentVariable($envVarName) if (-not [string]::IsNullOrWhiteSpace($envVarValue)) { Write-ToConsoleLog "[$key] - Already set via environment variable $envVarName" continue } $isPlaceholderValue = $currentValue -is [string] -and $currentValue -match '^\s*<.*>\s*$' $isSetViaEnvVarPlaceholder = $currentValue -is [string] -and $currentValue -like "Set via environment variable*" if (-not [string]::IsNullOrWhiteSpace($currentValue) -and -not $isPlaceholderValue -and -not $isSetViaEnvVarPlaceholder) { Write-ToConsoleLog "[$key] - Already set in configuration" continue } } $result = Read-InputValue -Key $key -CurrentValue $currentValue -SchemaInfo $schemaInfo -AzureContext $AzureContext $newValue = $result.Value $isSensitive = $result.IsSensitive # Handle sensitive values - store in env var, set placeholder in hashtable if ($isSensitive -and -not [string]::IsNullOrWhiteSpace($newValue)) { $envVarName = "TF_VAR_$key" [System.Environment]::SetEnvironmentVariable($envVarName, $newValue) $sensitiveEnvVars[$key] = $envVarName $inputsConfig[$key] = [string]"Set via environment variable $envVarName" $inputsUpdated = $true continue } # Determine if value changed (handle array comparison) $hasChanged = $false if ($currentValue -is [System.Collections.IList] -or $newValue -is [System.Collections.IList]) { $currentArray = @($currentValue) $newArray = @($newValue) if ($currentArray.Count -ne $newArray.Count) { $hasChanged = $true } else { for ($i = 0; $i -lt $currentArray.Count; $i++) { if ($currentArray[$i] -ne $newArray[$i]) { $hasChanged = $true break } } } } else { $hasChanged = $newValue -ne $currentValue } # Always store the value with the correct type for YAML serialization switch ($schemaType) { "boolean" { $typedValue = if ($newValue -is [bool]) { $newValue } else { $newValue.ToString().ToLower() -in @('true', 'yes', '1', 'y', 't') } $inputsConfig[$key] = [bool]$typedValue } "number" { $inputsConfig[$key] = [int]$newValue } "array" { $inputsConfig[$key] = [System.Collections.Generic.List[object]]@($newValue) } default { $inputsConfig[$key] = [string]$newValue } } if ($hasChanged) { $inputsUpdated = $true } } # Save updated inputs.yaml preserving comments and ordering if ($inputsUpdated) { # Serialize the updated ordered hashtable to YAML $serializedYaml = ($inputsConfig | ConvertTo-Yaml).TrimEnd() $serializedLines = $serializedYaml -split "`n" # Build a lookup from serialized YAML: key (with indentation) -> serialized line # Multi-line arrays are converted to inline format $serializedLookup = [ordered]@{} $currentLookupKey = $null $currentLookupKeyName = $null $currentLookupIndent = "" $pendingArrayItems = @() foreach ($sLine in $serializedLines) { if ($sLine -match '^(\s*)([\w_][\w_\-]*):(.*)$') { # Flush any pending array items from the previous key if ($currentLookupKey -and $pendingArrayItems.Count -gt 0) { $inlineArray = "[" + (($pendingArrayItems | ForEach-Object { "`"$_`"" }) -join ", ") + "]" $serializedLookup[$currentLookupKey] = "$currentLookupIndent${currentLookupKeyName}: $inlineArray" $pendingArrayItems = @() } $indent = $Matches[1] $keyName = $Matches[2] $lookupKey = "${indent}${keyName}" $currentLookupKey = $lookupKey $currentLookupKeyName = $keyName $currentLookupIndent = $indent $serializedLookup[$lookupKey] = $sLine } elseif ($sLine -match '^\s*- (.+)$') { # Array continuation line - collect for inline conversion $pendingArrayItems += $Matches[1] } } # Flush trailing array items if ($currentLookupKey -and $pendingArrayItems.Count -gt 0) { $inlineArray = "[" + (($pendingArrayItems | ForEach-Object { "`"$_`"" }) -join ", ") + "]" $serializedLookup[$currentLookupKey] = "$currentLookupIndent${currentLookupKeyName}: $inlineArray" } # Walk original file lines, merge comments with serialized values $originalLines = $inputsYamlContent -split "`n" $resultLines = @() foreach ($originalLine in $originalLines) { $trimmedLine = $originalLine.TrimStart() # Preserve blank lines, comment-only lines, and YAML document markers if ([string]::IsNullOrWhiteSpace($originalLine) -or $trimmedLine.StartsWith('#') -or $trimmedLine -eq '---') { $resultLines += $originalLine continue } # Data line - extract key and look up the serialized value if ($originalLine -match '^(\s*)([\w_][\w_\-]*):') { $indent = $Matches[1] $keyName = $Matches[2] $lookupKey = "${indent}${keyName}" # Extract inline comment from the original line $inlineComment = $null if ($originalLine -match '\S\s{2,}(#.*)$') { $inlineComment = $Matches[1] } if ($serializedLookup.Contains($lookupKey)) { $newLine = $serializedLookup[$lookupKey] # Format the value using our inline formatter for consistent output $hashtableValue = $null if ($indent -eq "" -and $inputsConfig.Contains($keyName)) { $hashtableValue = $inputsConfig[$keyName] } elseif ($indent.Length -gt 0) { # Nested value - find the parent key foreach ($parentKey in $inputsConfig.Keys) { if ($inputsConfig[$parentKey] -is [System.Collections.IDictionary] -and $inputsConfig[$parentKey].Contains($keyName)) { $hashtableValue = $inputsConfig[$parentKey][$keyName] break } } } # Use the formatted value for the line if ($null -ne $hashtableValue -and -not ($hashtableValue -is [System.Collections.IDictionary])) { $formattedValue = Format-YamlInlineValue -Value $hashtableValue $newLine = "${indent}${keyName}: $formattedValue" } if ($inlineComment) { $newLine = "$newLine $inlineComment" } $resultLines += $newLine } else { # Key not found in serialized output, keep original line $resultLines += $originalLine } } else { # Non-key data line (shouldn't normally happen), keep as-is $resultLines += $originalLine } } ($resultLines -join "`n") | Set-Content -Path $inputsYamlPath -Force -NoNewline Write-ToConsoleLog "Updated inputs.yaml" -IsSuccess # Display summary of sensitive environment variables if ($sensitiveEnvVars.Count -gt 0) { Write-ToConsoleLog "Sensitive values have been set as environment variables:" -IsWarning foreach ($varKey in $sensitiveEnvVars.Keys) { Write-ToConsoleLog "$varKey -> $($sensitiveEnvVars[$varKey])" -IsSelection -IndentLevel 1 } Write-ToConsoleLog "These environment variables are set for the current process only." Write-ToConsoleLog "The config file contains placeholders indicating the values are set via environment variables." } $configUpdated = $true } } return $configUpdated } } # SIG # Begin signature block # MIIoLgYJKoZIhvcNAQcCoIIoHzCCKBsCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDfbJDiHlLE1zAp # 6ZxjCISkt2z6zrfZPdmkta5p3ylMBqCCDXYwggX0MIID3KADAgECAhMzAAAEhV6Z # 7A5ZL83XAAAAAASFMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjUwNjE5MTgyMTM3WhcNMjYwNjE3MTgyMTM3WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDASkh1cpvuUqfbqxele7LCSHEamVNBfFE4uY1FkGsAdUF/vnjpE1dnAD9vMOqy # 5ZO49ILhP4jiP/P2Pn9ao+5TDtKmcQ+pZdzbG7t43yRXJC3nXvTGQroodPi9USQi # 9rI+0gwuXRKBII7L+k3kMkKLmFrsWUjzgXVCLYa6ZH7BCALAcJWZTwWPoiT4HpqQ # hJcYLB7pfetAVCeBEVZD8itKQ6QA5/LQR+9X6dlSj4Vxta4JnpxvgSrkjXCz+tlJ # 67ABZ551lw23RWU1uyfgCfEFhBfiyPR2WSjskPl9ap6qrf8fNQ1sGYun2p4JdXxe # UAKf1hVa/3TQXjvPTiRXCnJPAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUuCZyGiCuLYE0aU7j5TFqY05kko0w # RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW # MBQGA1UEBRMNMjMwMDEyKzUwNTM1OTAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci # tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG # CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0 # MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBACjmqAp2Ci4sTHZci+qk # tEAKsFk5HNVGKyWR2rFGXsd7cggZ04H5U4SV0fAL6fOE9dLvt4I7HBHLhpGdE5Uj # Ly4NxLTG2bDAkeAVmxmd2uKWVGKym1aarDxXfv3GCN4mRX+Pn4c+py3S/6Kkt5eS # DAIIsrzKw3Kh2SW1hCwXX/k1v4b+NH1Fjl+i/xPJspXCFuZB4aC5FLT5fgbRKqns # WeAdn8DsrYQhT3QXLt6Nv3/dMzv7G/Cdpbdcoul8FYl+t3dmXM+SIClC3l2ae0wO # lNrQ42yQEycuPU5OoqLT85jsZ7+4CaScfFINlO7l7Y7r/xauqHbSPQ1r3oIC+e71 # 5s2G3ClZa3y99aYx2lnXYe1srcrIx8NAXTViiypXVn9ZGmEkfNcfDiqGQwkml5z9 # nm3pWiBZ69adaBBbAFEjyJG4y0a76bel/4sDCVvaZzLM3TFbxVO9BQrjZRtbJZbk # C3XArpLqZSfx53SuYdddxPX8pvcqFuEu8wcUeD05t9xNbJ4TtdAECJlEi0vvBxlm # M5tzFXy2qZeqPMXHSQYqPgZ9jvScZ6NwznFD0+33kbzyhOSz/WuGbAu4cHZG8gKn # lQVT4uA2Diex9DMs2WHiokNknYlLoUeWXW1QrJLpqO82TLyKTbBM/oZHAdIc0kzo # STro9b3+vjn2809D0+SOOCVZMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg # Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03 # a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr # rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg # OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy # 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9 # sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh # dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k # A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB # w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn # Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90 # lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w # ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o # ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD # VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa # BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny # bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG # AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV # HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG # AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl # AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb # C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l # hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6 # I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0 # wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560 # STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam # ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa # J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah # XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA # 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt # Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr # /Xmfwb1tbWrJUnMTDXpQzTGCGg4wghoKAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAASFXpnsDlkvzdcAAAAABIUwDQYJYIZIAWUDBAIB # BQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIHkf0uXQy6O8Rxw2z7ngaVn7 # 7fYc6sEDHmP1fcmHNAitMEQGCisGAQQBgjcCAQwxNjA0oBSAEgBNAGkAYwByAG8A # cwBvAGYAdKEcgBpodHRwczovL3d3dy5taWNyb3NvZnQuY29tIDANBgkqhkiG9w0B # AQEFAASCAQBi8odBPW0sJt+NGnjxMv46PoExvCMFg/AFHt9I8qEVsR6afCWG1Z1j # iRKsJ88rasjVEQH9xHgJ6Wo564t8zp8xL9YortiT0D3xQB/C8fp7Y05EYLkZ1+LG # rkPPQEsWsdAQUILnH7V0DvsiXwQmfbXaveYRXMBXWDNLa+yJgU4B7ckEQJx1e+3h # wcWvuFZGQploVS1lenhytI7SCW1finaWlRmwh2/6LOa1SP6/ikqzahnbQ8zDXhgz # 1iJh0PhfQC28I3873KoVv8QHIEN8YHT/DSgMPrJT2XotBIsjTlgetxOKITokDoo+ # K7JmL/NDMEBfGD6S5JWya21WMg9IWGDloYIXljCCF5IGCisGAQQBgjcDAwExgheC # MIIXfgYJKoZIhvcNAQcCoIIXbzCCF2sCAQMxDzANBglghkgBZQMEAgEFADCCAVEG # CyqGSIb3DQEJEAEEoIIBQASCATwwggE4AgEBBgorBgEEAYRZCgMBMDEwDQYJYIZI # AWUDBAIBBQAEIAwNaXcBkvU9Efus2gx6HVNbbDRb1PFuPMv92st6FexcAgZplKxc # TEgYEjIwMjYwMzA2MjIyNDUxLjEzWjAEgAIB9KCB0aSBzjCByzELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFt # ZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOkRDMDAt # MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl # oIIR7TCCByAwggUIoAMCAQICEzMAAAIDux5cADhsdMoAAQAAAgMwDQYJKoZIhvcN # AQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV # BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG # A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcNMjUwMTMwMTk0 # MjQ2WhcNMjYwNDIyMTk0MjQ2WjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9u # czEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOkRDMDAtMDVFMC1EOTQ3MSUwIwYD # VQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG9w0B # AQEFAAOCAg8AMIICCgKCAgEAoZdDB+cAJzsfFIfEbYnRdCdMmhQxyWB06T70Udel # 9SsRg2H0/D63BowiwomjrtytQ5lCFOEXOaJZ3Y2qaTbjoM8FKI+N1W2yceTxU2P2 # tWfNLaalT9DqCiZVJHwz0gSxYF1o+lYGskQiDbS7FGrMtMOYMrA+yCz2bokI2nHu # SsQEoyn9jFV9anxM2AW0xjRIo0kAisMMnNHmr6+BaN1//rArrgLZE1orLFOuJPKy # utI7BkQKYhEnX7h69MlgJnO40zjzXhgMeigi9pLaZxnoCw3dSJROgbugUsACBR6+ # 8zsCJRaskLgntEkACwmyYbE/cvYsutUSQF7FNLtEwuWGJk0mxCO4NdHWMfFI/r4f # SJy6CmAuQ6Sm99dW2FXdG8rW85X00bJUUyYKLZ3wgCBjC6hKpPf9lURrvZJSYtY/ # Z1X6smB2KzDzgV3K0GFtI5ijYzi+OwmhAKzc4QwYmtcF3SQDSqjLyfKUHtpvP3Im # 8gzPtQVWarjQKL/TeLSReAArY19I41zQ1DLUmaFRUB/hZFnXz1sdbgSJHPe0fsUS # 7j41MqR2eQNwAC0pHuE2kQb270wWMlth3pzk+52CykzuI8OUKunMN2fc0ykj0Og+ # ZcomKXrOUUdjHTLyUuHwnDyRXmlTr7lhUkPxBrVQUoYZiwfuXsMxc3aX9VLiZrjk # E08CAwEAAaOCAUkwggFFMB0GA1UdDgQWBBSyKVlAfhHnkNvbFntFXc8VkBiSfTAf # BgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQ # hk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQl # MjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBe # MFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2Nl # cnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAM # BgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQE # AwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAkBDG3rA+kwtPEdKGAnUguOdgEKxn/zvP # RkOeArYBLG8c8Bg1VHJo1xXJ2iUkzXnQSlV5AYGsEaJz9S4MR+G881Y9nljZsxiM # DtRZYZXQDzhwMywRB0aEmeKXXRbWkMaGm1Pzdb1siAojetCLfOYJxeSQ+DDF8neq # UvHgAyIuk7Y34Cj6LplmtARUP2hM41K3zzda+3KyvqpJi87cPxDUu83pn8seJBkY # MGNVgXxapv5xZSQz0AYnKnlN3TqfYY+1qg9EXPv+FWesEI3rCMgpL+boVDcti4TQ # 4tpXmLQIiBaZo3zZOBp4C7wtk4/SKzjL9tEq8puSfxYe8lgIj3hrN8gN0GqY2U7X # 6+zX86QSCUOMU/4nOFhlqoRpUZVQSObujo8N2cUmQi4N70QuCmMqZIfBXSFqCoq4 # 4nRBpV7DTqPlD/2BuSoXm4rnUwcRnnHyQrrlLKSHUYUrRwELI7/3QKlgS5YaK6tj # gmj/sBYRN1j4J58eaX5b5bo6HD4LDduPvnXR65dztRRWm1vJtFJAx0igofEE8E5G # DsLvfYhMQVVpW2GUc9qjiAYy/6MxIbQgdGrioX0yy3rjRgVGgc/qGWfl/VABAqDI # ZBE42+mHzWiNU+71QGoroQaFfyQjkE/kWGa4MpMj6c6ZsDDRQQ9b3Vv9vavZ5E1q # BIXBDjtC/TcwggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZAAAAAAAVMA0GCSqG # SIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ # MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u # MTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkg # MjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU # aW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC # AgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4X # YDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTz # xXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7 # uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928jaTjkY+yOSxRnOlw # aQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3tpK56KTesy+uDRedG # bsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGaRnXN # xF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fzpk03 # dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9 # ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5 # UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReT # wDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZ # MBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8 # RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAE # VTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAww # CgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQD # AgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb # 186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29t # L3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoG # CCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZI # hvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9 # MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2Lpyp # glYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OO # PcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8 # DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmRsqlb30mjdAy87JGA # 0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8x1Rt # nWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjc # ZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq7 # 7EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJ # C4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328 # y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYID # UDCCAjgCAQEwgfmhgdGkgc4wgcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMx # JzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjpEQzAwLTA1RTAtRDk0NzElMCMGA1UE # AxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIaAxUA # za8UV/4s+rLNZQQlxvD9SxcQ9HuggYMwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFt # cCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsFAAIFAO1VkZYwIhgPMjAyNjAzMDYxNzQ3 # MDJaGA8yMDI2MDMwNzE3NDcwMlowdzA9BgorBgEEAYRZCgQBMS8wLTAKAgUA7VWR # lgIBADAKAgEAAgIKGAIB/zAHAgEAAgIYMTAKAgUA7VbjFgIBADA2BgorBgEEAYRZ # CgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0G # CSqGSIb3DQEBCwUAA4IBAQBtQw/sUVaPv0WT1fV7fgfhvRAjKvnQ7PPhTAPlHZdC # uvOg77CtlNnLcxdl5FxwQB5VKbG2rvIvUviVBUk6td5HZA/sa1W01o1e4Y5QjiYE # alwoG3xUjWS/wq2ECbvtiLAi2CG1vSDhwnJh6CDw0TGEPoCLlGgRyBz1X/H4/0rk # X/QHY5//Y0N+L1ho55HFiNyneHzdzAKgFVy20TtPPzT+cDCC+ca5m7i+EaAUasuG # kWR/DWW5tOnA7MkvbearjOOIkT1/m0QDTP6jAV0ORBn7UzDk0BqBZIu7zw/W2gLj # P4z0daQStdyZqyQ2YDvnV+B3oxIF6lVFZAT3hm/zanNvMYIEDTCCBAkCAQEwgZMw # fDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl # ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMd # TWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAIDux5cADhsdMoAAQAA # AgMwDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRAB # BDAvBgkqhkiG9w0BCQQxIgQgPHAAibG7R9t68+ykM+egs6oA0lWuHExA240Iy/5M # tl8wgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCBLA90bcZb2k8RTmWZ6UMNA # 5LD5lXbqOUsivYfcPvoTLTCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv # ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD # QSAyMDEwAhMzAAACA7seXAA4bHTKAAEAAAIDMCIEIB0lXZdbeoJyDW1EDOwV7ZBj # IBXJ8KiF1exr0YHTzan7MA0GCSqGSIb3DQEBCwUABIICAJfbHAMhs9ndF9+87Dli # 4KtC0AOY0QkHpkmyazz+Lx7NIPVqsKAtUxclznEWDi9hkJdXADHL4inuxoqX00RG # uCiO9S/o7jMKuDbI21XPsMEHBCIzW9OVRReBBowy5FTGVfCWu5MPk3Tlc8LVq5t4 # pwZejKMUm9EPUO4WcbRmVMhIKvkK6pPGr9tsyngiQhrVFl7gqWmqvhdZEoojfery # +ywMO/+aAGyHwEi+BZkjVwJDBP/3mL4S/2WEPHODbFaZJkRbmCEzdmHOvcOBgFI3 # lPgpy4oBFUeDeJBGEWcmmARJMKM8SwFYyplZQSwzf1oErREoGivHWzA0rczeQplj # BGkKDE19bxPS3A7XGacsl4+SmLLlOOATzs2qi76vuVVbGPlcXnOimrq/TOR0eqf7 # iJL269KER8jCKNGBxhLWprrJ1oBYuSaJjXZxHIxuWNoHVc2AG1rzI5VzlRTwSn75 # 2ti0m+AgEOd3KEAGDapc7Qh3PIc9/rj/5MqG2vnHB8LXPQZAcsMC6nyBXeOkOH5N # CSTC2nVVerkV5xlUmOHdoRl2Qj1lKgea8QDAevH1dIBTB+M7727sv2O4fo3QNUDu # 5Mf31rh1rUa6pBoFIlaxSip08rV4ExDOOsMYD3D/5gD5GY+g0L022uG9x0b2Inxb # 4OPXcTpPwMvU3Skq0C3IIeTP # SIG # End signature block |