public/Get-IvantiWCPolicy.ps1
|
<#
.SYNOPSIS Reads, decodes, and correlates Ivanti Workspace Control policy sets from a Building Block XML file. .DESCRIPTION Reads an Ivanti Workspace Control Building Block XML file, pre-loads all embedded ADMX/ADML templates, and processes each policy set found within the file. For each policy set it correlates the applied registry settings with their ADMX definitions (via Get-AdmxPolicySetting) and returns a structured PowerShell object per policy set. Supports two export modes via -ExportFor: - WEM: returns correlated policy data only (default). - AppVentiX: additionally returns an AppVentiXParams property containing pre-structured policy data ready to pass directly to New-AppVentiXGroupPolicy -PolicyInputObject. Policy state (Enabled/Disabled/Unconfigured) is determined in priority order: 1. POLICY:1/2 indicator from the embedded PolicySettings data. 2. Policy-level registry value compared against ADMX enabledValue/disabledValue. 3. Presence of element-level registry values (implies Enabled). List-type ADMX elements (values stored as numbered entries under a sub-key) are fully supported. Boolean elements with explicit trueValue/falseValue nodes are resolved correctly. .PARAMETER Path Path to the Ivanti Workspace Control Building Block XML file. .PARAMETER IncludeADMFiles If specified, includes the ADMX and ADML filenames and their base64-encoded content in the output for each policy set. Required when piping output to New-AppVentiXGroupPolicy. .PARAMETER ExportFor Target export format. 'AppVentiX' adds the AppVentiXParams property to each output object. Defaults to 'WEM'. .PARAMETER IncludePolicyDescription If specified, includes the ADMX ExplainText (policy description) in the PolicySettings output. .PARAMETER SaveResourceFiles If specified, saves the decoded ADMX/ADML files and the raw PolicySettings/RegistryFile data to disk at the path specified by -ExportPath. .PARAMETER ExportPath Directory path where decoded resource files are saved when -SaveResourceFiles is used. .EXAMPLE # Export policy data for use with AppVentiX $Policies = Get-IvantiWCPolicy -Path 'C:\temp\LAB-BB.xml' -IncludeADMFiles -ExportFor AppVentiX $result = $Policies | ForEach-Object { New-AppVentiXGroupPolicy ` -FriendlyName $_.Name ` -AdmxContent $_.ADMXContent ` -AdmxFileName $_.ADMX ` -AdmlContent $_.ADMLContent ` -AdmlFileName $_.ADML ` -PolicyInputObject $_.AppVentiXParams } .EXAMPLE # Inspect correlated policy data as JSON Get-IvantiWCPolicy -Path 'C:\temp\LAB-BB.xml' | ConvertTo-Json -Depth 5 .EXAMPLE # Save decoded resource files for inspection Get-IvantiWCPolicy -Path 'C:\temp\LAB-BB.xml' -SaveResourceFiles -ExportPath 'C:\temp\TempPolicy' .NOTES Function : Get-IvantiWCPolicy Author : John Billekens Copyright : (c) John Billekens Consultancy Version : 2026.0308.1500 #> function Get-IvantiWCPolicy { [CmdletBinding(DefaultParameterSetName = 'AppVentiX')] param( [Parameter(Mandatory = $true)] [string]$Path, [switch]$IncludeADMFiles, [ValidateSet("AppVentiX", "WEM")] [string]$ExportFor = "WEM", [switch]$IncludePolicyDescription, [Parameter(Mandatory = $true, ParameterSetName = 'Export')] [switch]$SaveResourceFiles, [Parameter(Mandatory = $true, ParameterSetName = 'Export')] [string]$ExportPath ) function Convert-HexToString { param([string]$HexString) if ([string]::IsNullOrEmpty($HexString)) { return '' } $bytes = for ($i = 0; $i -lt $HexString.Length; $i += 2) { [System.Convert]::ToByte($HexString.Substring($i, 2), 16) } return [System.Text.Encoding]::GetEncoding(1252).GetString($bytes) } function Convert-RegistryHexToValue { param( [string]$hexString, [string]$type ) # Extract hex bytes (remove hex(X): prefix and commas/spaces) $hexData = $hexString -replace '^hex\(\w+\):', '' -replace '[,\s]', '' if ([string]::IsNullOrEmpty($hexData)) { return $null } try { $bytes = for ($i = 0; $i -lt $hexData.Length; $i += 2) { [System.Convert]::ToByte($hexData.Substring($i, 2), 16) } switch ($type) { 'REG_SZ' { # hex(1) - null-terminated Unicode string return [System.Text.Encoding]::Unicode.GetString($bytes).TrimEnd([char]0) } 'REG_EXPAND_SZ' { # hex(2) - expandable string return [System.Text.Encoding]::Unicode.GetString($bytes).TrimEnd([char]0) } 'REG_BINARY' { # hex(3) or hex - binary data return [System.BitConverter]::ToString($bytes) } 'REG_DWORD' { # hex(4) - 32-bit number (little-endian) if ($bytes.Count -eq 4) { return [System.BitConverter]::ToUInt32($bytes, 0) } return $null } 'REG_MULTI_SZ' { # hex(7) - multiple null-terminated strings $fullString = [System.Text.Encoding]::Unicode.GetString($bytes) return ($fullString -split '\0' | Where-Object { $_ }) } 'REG_QWORD' { # hex(b) - 64-bit number (little-endian) if ($bytes.Count -eq 8) { return [System.BitConverter]::ToUInt64($bytes, 0) } return $null } default { return [System.BitConverter]::ToString($bytes) } } } catch { Write-Warning "Could not decode hex value for type $type. Error: $_" return $hexString } } function Convert-HexToStream { param([string]$HexString) if ([string]::IsNullOrEmpty($HexString)) { return $null } try { $bytes = for ($i = 0; $i -lt $HexString.Length; $i += 2) { [System.Convert]::ToByte($HexString.Substring($i, 2), 16) } # A MemoryStream is more efficient for large data than holding a giant string $memStream = New-Object System.IO.MemoryStream(, $bytes) return $memStream } catch { Write-Warning "Could not convert hex string to stream. Error: $_" return $null } } try { if (-not (Test-Path -Path $Path -PathType Leaf)) { throw "File not found at path: $Path" } # Resolve to absolute path for XmlDocument.Load() $absolutePath = (Resolve-Path -Path $Path).Path Write-Verbose "Loading XML file: $absolutePath" $xmlContent = New-Object System.Xml.XmlDocument $xmlContent.Load($absolutePath) # 1. Pre-load all ADM templates Write-Verbose "Pre-loading embedded ADMX/ADML templates..." $admTemplateStore = @{} $embeddedPolicies = $xmlContent.GetElementsByTagName('embeddedadm') $embeddedCount = $embeddedPolicies.Count Write-Verbose "Found $embeddedCount embedded template(s)" $templateCount = 0 foreach ($adm in $embeddedPolicies) { $fileName = $adm.filename if (-not $admTemplateStore.ContainsKey($fileName)) { $templateCount++ Write-Progress -Activity "Loading ADMX templates" -Status "$fileName" -PercentComplete ([int]($templateCount / [Math]::Max($embeddedCount, 1) * 100)) Write-Verbose "Loading template $templateCount/$embeddedCount`: $fileName" $admlFileName = $fileName -replace '.admx$', '.adml' $admxStream = Convert-HexToStream -HexString $adm.embeddedbinary $admlStream = Convert-HexToStream -HexString $adm.embeddedadml if ($null -eq $admxStream) { Write-Warning "Failed to decode ADMX template: $fileName" continue } try { $admxXml = New-Object System.Xml.XmlDocument $admxXml.Load($admxStream) $admlXml = New-Object System.Xml.XmlDocument if ($null -ne $admlStream) { $admlXml.Load($admlStream) } $admxBase64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($admxXml.OuterXml)) $admlBase64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($admlXml.OuterXml)) # Pre-load all policy settings from this template via Get-AdmxPolicySetting Write-Verbose " Indexing policy settings for: $fileName" $allPolicySettings = Get-AdmxPolicySetting -AdmxContent $admxBase64 -AdmlContent $admlBase64 -AdmxFileName $fileName -AdmlFileName $admlFileName -All # Build lookup: normalized RegistryKey\ValueName -> list of @{Policy; Element} objects # Policy-level valueName maps to Element=$null; element valueName maps to the element object # listLookup: normalized RegistryKey -> list of @{Policy; Element} for 'list' element types $policyLookup = [System.Collections.Hashtable]::new([System.StringComparer]::OrdinalIgnoreCase) $listLookup = [System.Collections.Hashtable]::new([System.StringComparer]::OrdinalIgnoreCase) foreach ($ps in $allPolicySettings) { # Policy-level (enabledValue/disabledValue controls this valueName) if (-not [string]::IsNullOrEmpty($ps.ValueName)) { $lookupKey = "$($ps.RegistryKey)\$($ps.ValueName)" if (-not $policyLookup.ContainsKey($lookupKey)) { $policyLookup[$lookupKey] = [System.Collections.Generic.List[object]]::new() } $policyLookup[$lookupKey].Add([PSCustomObject]@{ Policy = $ps; Element = $null }) } # Element-level entries foreach ($elem in $ps.Elements) { if ($elem.ElementType -eq 'list') { # List elements have no fixed valueName — index by their sub-key $listKey = $elem.RegistryKey if (-not $listLookup.ContainsKey($listKey)) { $listLookup[$listKey] = [System.Collections.Generic.List[object]]::new() } $listLookup[$listKey].Add([PSCustomObject]@{ Policy = $ps; Element = $elem }) } else { $elemLookupKey = "$($elem.RegistryKey)\$($elem.ValueName)" if (-not $policyLookup.ContainsKey($elemLookupKey)) { $policyLookup[$elemLookupKey] = [System.Collections.Generic.List[object]]::new() } $policyLookup[$elemLookupKey].Add([PSCustomObject]@{ Policy = $ps; Element = $elem }) } } } $admTemplateStore[$fileName] = [PSCustomObject]@{ ADMXFile = $fileName ADMLFile = $admlFileName ADMXContent = $admxBase64 ADMLContent = $admlBase64 PolicyLookup = $policyLookup ListLookup = $listLookup } if ($SaveResourceFiles.IsPresent -eq $true) { $id = [System.Guid]::NewGuid().ToString() if (-not (Test-Path -Path $ExportPath)) { New-Item -Path $ExportPath -ItemType Directory -Force | Out-Null } $admxExportPath = Join-Path -Path $ExportPath -ChildPath "$($id)_$($fileName)" $admlExportPath = Join-Path -Path $ExportPath -ChildPath "$($id)_$($admlFileName)" $admxXml.Save($admxExportPath) $admlXml.Save($admlExportPath) } } finally { # Ensure streams are always closed if ($null -ne $admxStream) { $admxStream.Dispose() } if ($null -ne $admlStream) { $admlStream.Dispose() } } } } # 2. Process each policy set $registryNodes = @($xmlContent.GetElementsByTagName('registry') | Where-Object { $_.type -eq 'policy' }) $totalPolicySets = $registryNodes.Count Write-Verbose "Processing $totalPolicySets policy set(s)" $policySetIndex = 0 foreach ($registryNode in $registryNodes) { $policySetIndex++ $policySetName = $registryNode.name Write-Progress -Activity "Processing policy sets" -Status "$policySetName ($policySetIndex/$totalPolicySets)" -PercentComplete ([int]($policySetIndex / [Math]::Max($totalPolicySets, 1) * 100)) Write-Verbose "Processing policy set $policySetIndex/$totalPolicySets`: $policySetName" $decodedPolicySettingsStr = (Convert-HexToString -HexString $registryNode.policysettings).TrimStart([char]0xFEFF) $decodedRegistryFileStr = (Convert-HexToString -HexString $registryNode.registryfile).TrimStart([char]0xFEFF) $Assignments = @(ConvertFrom-IvantiAccessControl -AccessControl $registryNode.accesscontrol -IWCComponentName $policySetName -IWCComponent "Policy") if ($SaveResourceFiles.IsPresent -eq $true) { $id = [System.Guid]::NewGuid().ToString() if (-not (Test-Path -Path $ExportPath)) { New-Item -Path $ExportPath -ItemType Directory -Force | Out-Null } $policySettingsExportPath = Join-Path -Path $ExportPath -ChildPath "$($id)_$($policySetName)_PolicySettings.txt" $decodedPolicySettingsStr | Out-File -FilePath $policySettingsExportPath -Encoding UTF8 $registryFileExportPath = Join-Path -Path $ExportPath -ChildPath "$($id)_$($policySetName)_RegistryFile.txt" $decodedRegistryFileStr | Out-File -FilePath $registryFileExportPath -Encoding UTF8 } $admxFileNameMatch = $decodedPolicySettingsStr | Select-String -Pattern "ADMFILENAME:(.*)" if (-not $admxFileNameMatch) { Write-Warning "Policy set '$policySetName' does not specify an ADMX template file (ADMFILENAME not found)" continue } $admxFileName = $admxFileNameMatch.Matches.Groups[1].Value.Trim() Write-Verbose " Using ADMX template: $admxFileName" # Parse PolicySettings.txt: build lookup DisplayName -> ConfiguredState # Format: POLICY:1:Class||Category|...|DisplayName (1=Enabled, 2=Disabled) $policyStateFromSettings = [System.Collections.Hashtable]::new([System.StringComparer]::OrdinalIgnoreCase) foreach ($settingsLine in $decodedPolicySettingsStr.Split([string[]]@("`r`n", "`n", "`r"), [StringSplitOptions]::RemoveEmptyEntries)) { if ($settingsLine -match '^POLICY:(\d+):[^|]+\|+(.+)$') { $stateCode = $matches[1] $displayPath = $matches[2] $displayName = ($displayPath -split '\|')[-1].Trim() $configuredState = switch ($stateCode) { '1' { 'Enabled' } '2' { 'Disabled' } default { 'Unconfigured' } } if (-not $policyStateFromSettings.ContainsKey($displayName)) { $policyStateFromSettings[$displayName] = $configuredState } } } Write-Verbose " Parsed $($policyStateFromSettings.Count) policy state(s) from PolicySettings" if (-not $admTemplateStore.ContainsKey($admxFileName)) { Write-Warning "Policy set '$policySetName' references ADMX template '$admxFileName' which was not found in embedded templates" continue } $currentTemplate = $admTemplateStore[$admxFileName] $policyLookup = $currentTemplate.PolicyLookup $listLookup = $currentTemplate.ListLookup $regLines = $decodedRegistryFileStr.Split([string[]]@("`r`n", "`n", "`r"), [StringSplitOptions]::None) $currentSectionHive = '' $currentSectionKey = '' $currentListEntry = $null # non-null when we're inside a list element sub-key section $currentListValues = $null # accumulates string values for the current list section # Collect all matched registry entries grouped by PolicyName # Key: PolicyName, Value: @{ Policy; PolicyLevelEntry; ElementEntries: list } $policyGroups = [System.Collections.Generic.Dictionary[string, hashtable]]::new() for ($i = 0; $i -lt $regLines.Length; $i++) { $line = $regLines[$i] # Track the current section header (optional leading ! = delete key marker) if ($line -match '^!?\[((HKEY_[^\\]+)\\(.+?))\]') { # If we just finished a list section, commit each item as a separate element entry if ($null -ne $currentListEntry -and $null -ne $currentListValues -and $currentListValues.Count -gt 0) { $listMatchedPolicy = $currentListEntry.Policy $listMatchedElement = $currentListEntry.Element if (-not $policyGroups.ContainsKey($listMatchedPolicy.PolicyName)) { $policyGroups[$listMatchedPolicy.PolicyName] = @{ Policy = $listMatchedPolicy PolicyLevelEntry = $null ElementEntries = [System.Collections.Generic.List[PSCustomObject]]::new() PFCategory = '' PFDisplayText = '' } } $policyGroups[$listMatchedPolicy.PolicyName].ElementEntries.Add([PSCustomObject]@{ ElementId = $listMatchedElement.ElementId ElementType = 'list' ConfiguredState = 'Enabled' Delete = $false RegistryHive = $currentSectionHive RegistryKey = $listMatchedElement.RegistryKey RegistryKeyPath = "$currentSectionHive\$($listMatchedElement.RegistryKey)" RegistryValueName = '' RegistryValue = @($currentListValues | ForEach-Object { $_.Value }) RegistryValueNames = @($currentListValues | ForEach-Object { $_.ValueName }) RegistryValueType = 'REG_SZ' RegistryType = $listMatchedElement.RegistryType Constraints = $listMatchedElement.Constraints EnumItems = $null TrueValue = $null FalseValue = $null }) Write-Verbose " Committed list element '$($listMatchedElement.ElementId)' with $($currentListValues.Count) item(s) for policy '$($listMatchedPolicy.PolicyName)'" } $currentSectionHive = $matches[2] $currentSectionKey = $matches[3] # Check if this new section is a list element sub-key $normalizedSectionKey = $currentSectionKey -replace '^(HKEY_LOCAL_MACHINE|HKLM|HKEY_CURRENT_USER|HKCU)\\', '' $listCandidates = $listLookup[$normalizedSectionKey] if ($listCandidates -and $listCandidates.Count -gt 0) { $currentListEntry = $listCandidates[0] # take first match; list sub-keys are unique $currentListValues = [System.Collections.Generic.List[object]]::new() Write-Verbose " Entering list element section: '$normalizedSectionKey' -> '$($currentListEntry.Policy.PolicyName)' element '$($currentListEntry.Element.ElementId)'" } else { $currentListEntry = $null $currentListValues = $null } } # Handle deletion markers $isDeletion = $false if ($line.TrimStart().StartsWith('!"')) { $isDeletion = $true $line = $line.TrimStart().Substring(1) Write-Verbose " Found deletion marker at line $($i + 1)" } if ($line -match '^"([^"]+)"=(.+)') { $policyNameFromReg = $matches[1] $rawValue = $matches[2].Trim() # If we're inside a list element section, collect each item as {ValueName; Value} if ($null -ne $currentListEntry -and $policyNameFromReg -match '^\d+$') { $itemValue = if ($rawValue.StartsWith('"') -and $rawValue.EndsWith('"')) { $rawValue.Substring(1, $rawValue.Length - 2) } else { $rawValue } $currentListValues.Add([PSCustomObject]@{ ValueName = $policyNameFromReg; Value = $itemValue }) continue } # Look for PF comment on the next line $pfComment = '' $pfCategory = '' $pfDisplayText = '' if (($i + 1) -lt $regLines.Length -and $regLines[$i + 1].TrimStart().StartsWith(';<PF>')) { if ($regLines[$i + 1] -match ';<PF>(.*)</PF>') { $pfComment = $matches[1] if ($pfComment -match '^(HKEY_[^\\]+)\\([^\\]+)\\(.+)$') { $pfCategory = $matches[2] $pfDisplayText = $matches[3] } } } $registryValue = $null $registryValueType = 'Unknown' if ($rawValue.StartsWith('dword:') -or $rawValue.StartsWith('qword:')) { $registryValueType = if ($rawValue.StartsWith('dword:')) { 'REG_DWORD' } else { 'REG_QWORD' } try { $registryValue = [uint64]("0x" + $rawValue.Split(':')[1]) } catch { Write-Warning "Could not parse numeric value for '$policyNameFromReg': $rawValue. Error: $_" $registryValue = $rawValue $registryValueType = 'Unknown' } } elseif ($rawValue.StartsWith('"') -and $rawValue.EndsWith('"')) { $registryValueType = 'REG_SZ' $registryValue = $rawValue.Substring(1, $rawValue.Length - 2) } elseif ($rawValue.StartsWith('hex')) { if ($rawValue.StartsWith('hex(1):')) { $registryValueType = 'REG_SZ' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_SZ' } elseif ($rawValue.StartsWith('hex(2):')) { $registryValueType = 'REG_EXPAND_SZ' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_EXPAND_SZ' } elseif ($rawValue.StartsWith('hex(3):') -or $rawValue.StartsWith('hex:')) { $registryValueType = 'REG_BINARY' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_BINARY' } elseif ($rawValue.StartsWith('hex(4):')) { $registryValueType = 'REG_DWORD' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_DWORD' } elseif ($rawValue.StartsWith('hex(7):')) { $registryValueType = 'REG_MULTI_SZ' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_MULTI_SZ' } elseif ($rawValue.StartsWith('hex(b):')) { $registryValueType = 'REG_QWORD' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_QWORD' } else { $registryValueType = 'REG_BINARY' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_BINARY' } } else { $registryValueType = 'REG_SZ' $registryValue = $rawValue } # Lookup policy via normalized key\valueName $normalizedKey = $currentSectionKey -replace '^(HKEY_LOCAL_MACHINE|HKLM|HKEY_CURRENT_USER|HKCU)\\', '' $lookupKey = "$normalizedKey\$policyNameFromReg" $candidatePolicies = $policyLookup[$lookupKey] $matchedEntry = $null if ($candidatePolicies -and $candidatePolicies.Count -gt 1) { $policyNames = ($candidatePolicies | ForEach-Object { $_.Policy.PolicyName }) -join ', ' if ($pfComment) { foreach ($candidate in $candidatePolicies) { if ($pfComment -match [regex]::Escape($candidate.Policy.RegistryKey)) { $matchedEntry = $candidate Write-Verbose " Selected '$($candidate.Policy.PolicyName)' from multiple matches ($policyNames) based on registry key path match" break } } } if (-not $matchedEntry) { $nonRecommended = $candidatePolicies | Where-Object { $_.Policy.PolicyName -notmatch '_recommended$' } | Select-Object -First 1 if ($nonRecommended) { $matchedEntry = $nonRecommended Write-Verbose " Selected '$($matchedEntry.Policy.PolicyName)' from multiple matches ($policyNames) - preferred non-recommended policy" } } if (-not $matchedEntry) { $matchedEntry = $candidatePolicies[0] Write-Warning " Multiple policies found for '$lookupKey': $policyNames. Selected '$($matchedEntry.Policy.PolicyName)' (first match)" } } else { $matchedEntry = $candidatePolicies | Select-Object -First 1 } if ($matchedEntry) { $matchedPolicy = $matchedEntry.Policy $matchedElement = $matchedEntry.Element # $null = policy-level match Write-Verbose " Matched policy: $($matchedPolicy.PolicyName) ($(if ($null -ne $matchedElement) { $matchedElement.ElementType } else { 'policy-level' }))" # Ensure group entry exists for this policy if (-not $policyGroups.ContainsKey($matchedPolicy.PolicyName)) { $policyGroups[$matchedPolicy.PolicyName] = @{ Policy = $matchedPolicy PolicyLevelEntry = $null # filled when policy-level valueName is matched ElementEntries = [System.Collections.Generic.List[PSCustomObject]]::new() PFCategory = $pfCategory PFDisplayText = $pfDisplayText } } if ($null -eq $matchedElement) { # Policy-level match (NoAutoUpdate, etc.) — determines ConfiguredState of the policy $configuredState = 'Unconfigured' if ($null -ne $matchedPolicy.EnabledValue -and "$registryValue" -eq "$($matchedPolicy.EnabledValue)") { $configuredState = 'Enabled' } elseif ($null -ne $matchedPolicy.DisabledValue -and "$registryValue" -eq "$($matchedPolicy.DisabledValue)") { $configuredState = 'Disabled' } elseif ($registryValueType -in @('REG_DWORD', 'REG_QWORD')) { $configuredState = if ($registryValue -ne 0) { 'Enabled' } else { 'Disabled' } } else { $configuredState = 'Enabled' } $policyGroups[$matchedPolicy.PolicyName].PolicyLevelEntry = [PSCustomObject]@{ ConfiguredState = $configuredState Delete = $isDeletion RegistryHive = $currentSectionHive RegistryKey = $matchedPolicy.RegistryKey RegistryKeyPath = "$currentSectionHive\$($matchedPolicy.RegistryKey)" RegistryValueName = $policyNameFromReg RegistryValue = $registryValue RegistryValueType = $registryValueType } } else { # Element-level match $elemType = $matchedElement.ElementType # Determine ConfiguredState for boolean elements with explicit trueValue/falseValue $configuredState = if ($elemType -eq 'boolean' -and $null -ne $matchedElement.TrueValue -and $null -ne $matchedElement.FalseValue) { if ("$registryValue" -eq "$($matchedElement.TrueValue)") { 'Enabled' } elseif ("$registryValue" -eq "$($matchedElement.FalseValue)") { 'Disabled' } else { 'Enabled' } # presence implies enabled } else { 'Enabled' # presence of any element value means policy is enabled } $elemEntry = [PSCustomObject]@{ ElementId = $matchedElement.ElementId ElementType = $elemType ConfiguredState = $configuredState Delete = $isDeletion RegistryHive = $currentSectionHive RegistryKey = $matchedElement.RegistryKey RegistryKeyPath = "$currentSectionHive\$($matchedElement.RegistryKey)" RegistryValueName = $policyNameFromReg RegistryValue = $registryValue RegistryValueType = $registryValueType RegistryType = $matchedElement.RegistryType Constraints = $matchedElement.Constraints EnumItems = $matchedElement.EnumItems TrueValue = $matchedElement.TrueValue FalseValue = $matchedElement.FalseValue } $policyGroups[$matchedPolicy.PolicyName].ElementEntries.Add($elemEntry) } } else { Write-Warning " Registry value '$policyNameFromReg' does not match any policy in ADMX template '$admxFileName'" } } } # Commit any pending list section after the last line if ($null -ne $currentListEntry -and $null -ne $currentListValues -and $currentListValues.Count -gt 0) { $listMatchedPolicy = $currentListEntry.Policy $listMatchedElement = $currentListEntry.Element if (-not $policyGroups.ContainsKey($listMatchedPolicy.PolicyName)) { $policyGroups[$listMatchedPolicy.PolicyName] = @{ Policy = $listMatchedPolicy PolicyLevelEntry = $null ElementEntries = [System.Collections.Generic.List[PSCustomObject]]::new() PFCategory = '' PFDisplayText = '' } } $policyGroups[$listMatchedPolicy.PolicyName].ElementEntries.Add([PSCustomObject]@{ ElementId = $listMatchedElement.ElementId ElementType = 'list' ConfiguredState = 'Enabled' Delete = $false RegistryHive = $currentSectionHive RegistryKey = $listMatchedElement.RegistryKey RegistryKeyPath = "$currentSectionHive\$($listMatchedElement.RegistryKey)" RegistryValueName = '' RegistryValue = @($currentListValues | ForEach-Object { $_.Value }) RegistryValueNames = @($currentListValues | ForEach-Object { $_.ValueName }) RegistryValueType = 'REG_SZ' RegistryType = $listMatchedElement.RegistryType Constraints = $listMatchedElement.Constraints EnumItems = $null TrueValue = $null FalseValue = $null }) Write-Verbose " Committed list element '$($listMatchedElement.ElementId)' with $($currentListValues.Count) item(s) for policy '$($listMatchedPolicy.PolicyName)'" } # Build correlated settings: 1 object per policy $correlatedSettings = foreach ($group in $policyGroups.Values) { $admxPolicy = $group.Policy $policyEntry = $group.PolicyLevelEntry $elementEntries = $group.ElementEntries # Determine overall policy ConfiguredState # Priority: 1) PolicySettings.txt POLICY:1/2 indicator, 2) policy-level registry entry, 3) element presence $overallState = if ($policyStateFromSettings.ContainsKey($admxPolicy.DisplayName)) { $policyStateFromSettings[$admxPolicy.DisplayName] } elseif ($null -ne $policyEntry) { $policyEntry.ConfiguredState } elseif ($elementEntries.Count -gt 0) { 'Enabled' } else { 'Unconfigured' } [PSCustomObject]([ordered]@{ PolicyName = $admxPolicy.PolicyName DisplayName = $admxPolicy.DisplayName ConfiguredState = $overallState Class = $admxPolicy.Class Category = $admxPolicy.Category SupportedOn = $admxPolicy.SupportedOn Description = if ($IncludePolicyDescription) { $admxPolicy.ExplainText } else { $null } EnabledValue = $admxPolicy.EnabledValue DisabledValue = $admxPolicy.DisabledValue RegistryHive = if ($null -ne $policyEntry) { $policyEntry.RegistryHive } else { $null } RegistryKey = $admxPolicy.RegistryKey RegistryKeyPath = if ($null -ne $policyEntry) { $policyEntry.RegistryKeyPath } else { $null } RegistryValueName = if ($null -ne $policyEntry) { $policyEntry.RegistryValueName } else { $null } RegistryValue = if ($null -ne $policyEntry) { $policyEntry.RegistryValue } else { $null } RegistryValueType = if ($null -ne $policyEntry) { $policyEntry.RegistryValueType } else { $null } Delete = if ($null -ne $policyEntry) { $policyEntry.Delete } else { $false } Elements = if ($elementEntries.Count -gt 0) { $elementEntries.ToArray() } else { @() } PFCategory = $group.PFCategory PFDisplayText = $group.PFDisplayText }) } # Extract policy set metadata $runOnce = ($registryNode.runonce -eq 'yes') $setEnabled = ($registryNode.enabled -eq 'yes') $guid = $registryNode.guid $policySetOutput = [ordered]@{ Name = $registryNode.name Description = $registryNode.description RunOnce = $runOnce Enabled = $setEnabled GUID = $guid PolicySettings = $correlatedSettings } if ($ExportFor -eq 'AppVentiX') { $policySetOutput.AppVentiXAssignments = $Assignments $policySetOutput.AppVentiXParams = @() foreach ($policySetting in $correlatedSettings) { # Element-level registry entries $AppVentiXPolicyElements = @() $AppVentiXPolicyRegistryKeys = @() if ((-not [string]::IsNullOrEmpty($policySetting.RegistryHive)) -and (-not [string]::IsNullOrEmpty($policySetting.RegistryKey)) -and (-not [string]::IsNullOrEmpty($policySetting.RegistryValueName)) ) { $AppVentiXPolicyRegistryKeys += [PSCustomObject]@{ RootKey = $policySetting.RegistryHive KeyPath = $policySetting.RegistryKey ValueName = $policySetting.RegistryValueName ValueData = $policySetting.RegistryValue ValueType = $policySetting.RegistryValueType Action = "Set" DeleteKey = $policySetting.Delete } } foreach ($element in $policySetting.Elements) { if ($element.ElementType -eq 'list') { $AppVentiXPolicyElements += [PSCustomObject]@{ ElementId = $element.ElementId RegistryKey = $element.RegistryKey RegistryValueName = '' Value = $element.RegistryValue -join [System.Environment]::NewLine ValueType = $element.RegistryValueType } if (-not [string]::IsNullOrEmpty($element.RegistryHive) -and -not [string]::IsNullOrEmpty($element.RegistryKey)) { for ($idx = 0; $idx -lt $element.RegistryValue.Count; $idx++) { $AppVentiXPolicyRegistryKeys += [PSCustomObject]@{ RootKey = $element.RegistryHive KeyPath = $element.RegistryKey ValueName = $element.RegistryValueNames[$idx] ValueData = $element.RegistryValue[$idx] ValueType = $element.RegistryType Action = "Set" DeleteKey = $element.Delete } } } } else { $ElementValue = $null $ElementValueType = $element.RegistryValueType if ($null -ne $element.EnumItems -and $element.EnumItems.Count -gt 0) { try { #$ElementValue = ($element.EnumItems | Where-Object { $_.RegistryValue -eq $element.RegistryValue }).DisplayName $ElementValue = $element.RegistryValue $ElementValueType = 'REG_SZ' } catch { $null } } elseif ($element.RegistryValueType -in @('REG_DWORD', 'REG_QWORD')) { $ElementValue = $element.RegistryValue -ne 0 } elseif ($element.RegistryValueType -eq 'REG_SZ') { $ElementValue = $element.RegistryValue } else { Write-Warning "Policy '$($registryNode.name)' Element '$($element.ElementId)' has unsupported RegistryValueType '$($element.RegistryValueType)' for AppVentiX export. Contact AppventiX Support for assistance." } $AppVentiXPolicyElements += [PSCustomObject]@{ ElementId = $element.ElementId RegistryKey = $element.RegistryKey RegistryValueName = $element.RegistryValueName Value = $ElementValue ValueType = $ElementValueType } if ((-not [string]::IsNullOrEmpty($element.RegistryHive)) -and (-not [string]::IsNullOrEmpty($element.RegistryKey)) -and (-not [string]::IsNullOrEmpty($element.RegistryValueName))) { $AppVentiXPolicyRegistryKeys += [PSCustomObject]@{ RootKey = $element.RegistryHive KeyPath = $element.RegistryKey ValueName = $element.RegistryValueName ValueData = $element.RegistryValue ValueType = $element.RegistryType Action = "Set" DeleteKey = $element.Delete } } } } # Policy-level registry entry if ($null -ne $policySetting.PolicyName) { $policySetOutput.AppVentiXParams += [PSCustomObject]@{ PolicyName = $policySetting.PolicyName PolicyDisplayName = $policySetting.DisplayName PolicyKey = $policySetting.RegistryKey PolicyValueName = $policySetting.RegistryValueName Enabled = $policySetting.ConfiguredState -eq 'Enabled' Elements = @($AppVentiXPolicyElements) RegistryEntries = @($AppVentiXPolicyRegistryKeys) } } } } if ($ExportFor -eq 'WEM') { Write-Warning "WEM export format is not implemented yet!" } if ($IncludeADMFiles) { $policySetOutput.ADMX = $currentTemplate.ADMXFile $policySetOutput.ADML = $currentTemplate.ADMLFile $policySetOutput.ADMXContent = $currentTemplate.ADMXContent $policySetOutput.ADMLContent = $currentTemplate.ADMLContent } Write-Verbose "Completed processing policy set: $policySetName" Write-Output ([PSCustomObject]$policySetOutput) } Write-Progress -Activity "Processing policy sets" -Completed Write-Verbose "Successfully processed $totalPolicySets policy set(s)" } catch { $resolvedPath = Resolve-Path -Path $Path -ErrorAction SilentlyContinue $filePath = if ($resolvedPath) { $resolvedPath.Path } else { $Path } $errorDetails = @( "Error processing Ivanti policy file", "File: $filePath", "Error: $($_.Exception.Message)", "Line: $($_.InvocationInfo.ScriptLineNumber)", "Position: $($_.InvocationInfo.PositionMessage)" ) Write-Error ($errorDetails -join "`n") throw } } # SIG # Begin signature block # MII6wAYJKoZIhvcNAQcCoII6sTCCOq0CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBDlcQarG9UobQ1 # Fw+LGianBCOvhwmNJ6NZfHeI1A2E0qCCIuQwggXMMIIDtKADAgECAhBUmNLR1FsZ # lUgTecgRwIeZMA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNVBAYTAlVTMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jvc29mdCBJZGVu # dGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAy # MDAeFw0yMDA0MTYxODM2MTZaFw00NTA0MTYxODQ0NDBaMHcxCzAJBgNVBAYTAlVT # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jv # c29mdCBJZGVudGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRo # b3JpdHkgMjAyMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALORKgeD # Bmf9np3gx8C3pOZCBH8Ppttf+9Va10Wg+3cL8IDzpm1aTXlT2KCGhFdFIMeiVPvH # or+Kx24186IVxC9O40qFlkkN/76Z2BT2vCcH7kKbK/ULkgbk/WkTZaiRcvKYhOuD # PQ7k13ESSCHLDe32R0m3m/nJxxe2hE//uKya13NnSYXjhr03QNAlhtTetcJtYmrV # qXi8LW9J+eVsFBT9FMfTZRY33stuvF4pjf1imxUs1gXmuYkyM6Nix9fWUmcIxC70 # ViueC4fM7Ke0pqrrBc0ZV6U6CwQnHJFnni1iLS8evtrAIMsEGcoz+4m+mOJyoHI1 # vnnhnINv5G0Xb5DzPQCGdTiO0OBJmrvb0/gwytVXiGhNctO/bX9x2P29Da6SZEi3 # W295JrXNm5UhhNHvDzI9e1eM80UHTHzgXhgONXaLbZ7LNnSrBfjgc10yVpRnlyUK # xjU9lJfnwUSLgP3B+PR0GeUw9gb7IVc+BhyLaxWGJ0l7gpPKWeh1R+g/OPTHU3mg # trTiXFHvvV84wRPmeAyVWi7FQFkozA8kwOy6CXcjmTimthzax7ogttc32H83rwjj # O3HbbnMbfZlysOSGM1l0tRYAe1BtxoYT2v3EOYI9JACaYNq6lMAFUSw0rFCZE4e7 # swWAsk0wAly4JoNdtGNz764jlU9gKL431VulAgMBAAGjVDBSMA4GA1UdDwEB/wQE # AwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIftJqhSobyhmYBAcnz1AQ # T2ioojAQBgkrBgEEAYI3FQEEAwIBADANBgkqhkiG9w0BAQwFAAOCAgEAr2rd5hnn # LZRDGU7L6VCVZKUDkQKL4jaAOxWiUsIWGbZqWl10QzD0m/9gdAmxIR6QFm3FJI9c # Zohj9E/MffISTEAQiwGf2qnIrvKVG8+dBetJPnSgaFvlVixlHIJ+U9pW2UYXeZJF # xBA2CFIpF8svpvJ+1Gkkih6PsHMNzBxKq7Kq7aeRYwFkIqgyuH4yKLNncy2RtNwx # AQv3Rwqm8ddK7VZgxCwIo3tAsLx0J1KH1r6I3TeKiW5niB31yV2g/rarOoDXGpc8 # FzYiQR6sTdWD5jw4vU8w6VSp07YEwzJ2YbuwGMUrGLPAgNW3lbBeUU0i/OxYqujY # lLSlLu2S3ucYfCFX3VVj979tzR/SpncocMfiWzpbCNJbTsgAlrPhgzavhgplXHT2 # 6ux6anSg8Evu75SjrFDyh+3XOjCDyft9V77l4/hByuVkrrOj7FjshZrM77nq81YY # uVxzmq/FdxeDWds3GhhyVKVB0rYjdaNDmuV3fJZ5t0GNv+zcgKCf0Xd1WF81E+Al # GmcLfc4l+gcK5GEh2NQc5QfGNpn0ltDGFf5Ozdeui53bFv0ExpK91IjmqaOqu/dk # ODtfzAzQNb50GQOmxapMomE2gj4d8yu8l13bS3g7LfU772Aj6PXsCyM2la+YZr9T # 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggcGMIIE7qADAgECAhMzAAfM8rDv # Jyd7QZv4AAAAB8zyMA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ # RCBWZXJpZmllZCBDUyBFT0MgQ0EgMDIwHhcNMjYwNDAyMjE0MTIwWhcNMjYwNDA1 # MjE0MTIwWjCBgzELMAkGA1UEBhMCTkwxFjAUBgNVBAgTDU5vb3JkLUJyYWJhbnQx # EjAQBgNVBAcTCVNjaGlqbmRlbDEjMCEGA1UEChMaSm9obiBCaWxsZWtlbnMgQ29u # c3VsdGFuY3kxIzAhBgNVBAMTGkpvaG4gQmlsbGVrZW5zIENvbnN1bHRhbmN5MIIB # ojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAql2zC5qD+WbLZzawVOEM6hmw # E525pZhueIRBk85Br6ZG8FoUZl7WzaPQV6JlW6kukWABJbvNbIKzQnLhu+SmCtBF # 5OA+rjaAREtoajEbtuL+N7rmNVrPTe7POYz2lgLn3VL/0l+xTMI402gfo/Vvha2H # ItsKRA93A7FHmWxnnhyA7p2ucpLfJNdNoCK1XsB22sNdhTqV8/TWRTuGzYP+FvTp # jhdcq/xyy16jKdwIgNOXCCAU9U4EO1TLR1WTTmxQNOWy5dNdP48HYLiACx/d9Gf1 # EVytoAgxmsNon12TmLU/FW1KUddP91DcbCmvEg0Zmab/UBPg0bRRufv8oGeJqnb9 # bcCUxCH99cPAvIe0MLg4qCtRM80fA36yz4/dfIC7xowKEUxhR7/kWUfg+3mKA2nJ # F6qSv3+llYtt7O6GRPWD40Rk9LGbSQD3+uCuAIBUNqh4Sokq1q+j+8jjU4yBNFBc # tL1HsI6KXgTLWBO81v+mX+Fs62Euo8AfRByW7HhRAgMBAAGjggIZMIICFTAMBgNV # HRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDA8BgNVHSUENTAzBgorBgEEAYI3YQEA # BggrBgEFBQcDAwYbKwYBBAGCN2G789NTgYr4ukmC0/31KIOytcN0MB0GA1UdDgQW # BBQKkf4WVoYJs/qIk34nGHoMkkbjSzAfBgNVHSMEGDAWgBRln1HOhWh/L4pFiKrd # pzG7Hg0AXjBnBgNVHR8EYDBeMFygWqBYhlZodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ1MlMjBF # T0MlMjBDQSUyMDAyLmNybDCBpQYIKwYBBQUHAQEEgZgwgZUwZAYIKwYBBQUHMAKG # WGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0 # JTIwSUQlMjBWZXJpZmllZCUyMENTJTIwRU9DJTIwQ0ElMjAwMi5jcnQwLQYIKwYB # BQUHMAGGIWh0dHA6Ly9vbmVvY3NwLm1pY3Jvc29mdC5jb20vb2NzcDBmBgNVHSAE # XzBdMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wCAYGZ4EMAQQB # MA0GCSqGSIb3DQEBDAUAA4ICAQC74nf6TvL5WCfrJh27QL0oRpanrcasjQ1NTjWc # SfyFdOv0IxPLaTcDfmin4wwOwgESPhnSPNWDwFf7tatAOG6pTL4MG2Op+izJPbGa # ap0Hht3E0qTTsgaoxC2CEgnfeInM2SCKIbf7ymTd76TfqQSDUQdz25Z343yKOPLT # 5WI/krGe4zCQh+ObMqhTfRTi31YQa+k9fRCALCGcVuu6nrfEC36y5zh8OmxbmawY # L/CgWg2V5OYx5EA3WXgFnJbgrt3YpL6rxNKcFTvqmqEkc5X1g6CucGXLkAH1x2CC # HoPQ/D5212vdFoPXLhHjASEbIi5VyzA77rFJF1ahcWO+pHI5YyQ4pvVrPCQ2im1D # vsihP12hTrlHxdSQnB57pBvKHPRyZdKIxl0eurYdsNIqdspSi0VuWbLB+xUwJhZf # cSmFBg9uIGVrQrt9MHAKzmcSAJQJn70BmaMmOgR5JbYsDOU4TIRg0p7h5XKWTvso # 1wGR/Ondg7CdFb68kfjNhUAZtCUNd4HdxcgVqkeaLV6teIpNChYu2EUuzOAG7P1V # hdz3fhn6WoKU6Yaj6mkIPOcBBJzM3ecoriYrrg2GQePxgWJltU6+zwA2PRrqzUzJ # Brkln75enYK+/KjaCrNE98LiX2/aHHkFDCxd2fwl47iSkdSR57klynfkL+28Lf2e # WhjDFzCCBwYwggTuoAMCAQICEzMAB8zysO8nJ3tBm/gAAAAHzPIwDQYJKoZIhvcN # AQEMBQAwWjELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh # dGlvbjErMCkGA1UEAxMiTWljcm9zb2Z0IElEIFZlcmlmaWVkIENTIEVPQyBDQSAw # MjAeFw0yNjA0MDIyMTQxMjBaFw0yNjA0MDUyMTQxMjBaMIGDMQswCQYDVQQGEwJO # TDEWMBQGA1UECBMNTm9vcmQtQnJhYmFudDESMBAGA1UEBxMJU2NoaWpuZGVsMSMw # IQYDVQQKExpKb2huIEJpbGxla2VucyBDb25zdWx0YW5jeTEjMCEGA1UEAxMaSm9o # biBCaWxsZWtlbnMgQ29uc3VsdGFuY3kwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw # ggGKAoIBgQCqXbMLmoP5ZstnNrBU4QzqGbATnbmlmG54hEGTzkGvpkbwWhRmXtbN # o9BXomVbqS6RYAElu81sgrNCcuG75KYK0EXk4D6uNoBES2hqMRu24v43uuY1Ws9N # 7s85jPaWAufdUv/SX7FMwjjTaB+j9W+FrYci2wpED3cDsUeZbGeeHIDuna5ykt8k # 102gIrVewHbaw12FOpXz9NZFO4bNg/4W9OmOF1yr/HLLXqMp3AiA05cIIBT1TgQ7 # VMtHVZNObFA05bLl010/jwdguIALH930Z/URXK2gCDGaw2ifXZOYtT8VbUpR10/3 # UNxsKa8SDRmZpv9QE+DRtFG5+/ygZ4mqdv1twJTEIf31w8C8h7QwuDioK1EzzR8D # frLPj918gLvGjAoRTGFHv+RZR+D7eYoDackXqpK/f6WVi23s7oZE9YPjRGT0sZtJ # APf64K4AgFQ2qHhKiSrWr6P7yONTjIE0UFy0vUewjopeBMtYE7zW/6Zf4WzrYS6j # wB9EHJbseFECAwEAAaOCAhkwggIVMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQD # AgeAMDwGA1UdJQQ1MDMGCisGAQQBgjdhAQAGCCsGAQUFBwMDBhsrBgEEAYI3Ybvz # 01OBivi6SYLT/fUog7K1w3QwHQYDVR0OBBYEFAqR/hZWhgmz+oiTficYegySRuNL # MB8GA1UdIwQYMBaAFGWfUc6FaH8vikWIqt2nMbseDQBeMGcGA1UdHwRgMF4wXKBa # oFiGVmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29m # dCUyMElEJTIwVmVyaWZpZWQlMjBDUyUyMEVPQyUyMENBJTIwMDIuY3JsMIGlBggr # BgEFBQcBAQSBmDCBlTBkBggrBgEFBQcwAoZYaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ1Ml # MjBFT0MlMjBDQSUyMDAyLmNydDAtBggrBgEFBQcwAYYhaHR0cDovL29uZW9jc3Au # bWljcm9zb2Z0LmNvbS9vY3NwMGYGA1UdIARfMF0wUQYMKwYBBAGCN0yDfQEBMEEw # PwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9j # cy9SZXBvc2l0b3J5Lmh0bTAIBgZngQwBBAEwDQYJKoZIhvcNAQEMBQADggIBALvi # d/pO8vlYJ+smHbtAvShGlqetxqyNDU1ONZxJ/IV06/QjE8tpNwN+aKfjDA7CARI+ # GdI81YPAV/u1q0A4bqlMvgwbY6n6LMk9sZpqnQeG3cTSpNOyBqjELYISCd94iczZ # IIoht/vKZN3vpN+pBINRB3PblnfjfIo48tPlYj+SsZ7jMJCH45syqFN9FOLfVhBr # 6T19EIAsIZxW67qet8QLfrLnOHw6bFuZrBgv8KBaDZXk5jHkQDdZeAWcluCu3dik # vqvE0pwVO+qaoSRzlfWDoK5wZcuQAfXHYIIeg9D8PnbXa90Wg9cuEeMBIRsiLlXL # MDvusUkXVqFxY76kcjljJDim9Ws8JDaKbUO+yKE/XaFOuUfF1JCcHnukG8oc9HJl # 0ojGXR66th2w0ip2ylKLRW5ZssH7FTAmFl9xKYUGD24gZWtCu30wcArOZxIAlAmf # vQGZoyY6BHkltiwM5ThMhGDSnuHlcpZO+yjXAZH86d2DsJ0VvryR+M2FQBm0JQ13 # gd3FyBWqR5otXq14ik0KFi7YRS7M4Abs/VWF3Pd+GfpagpTphqPqaQg85wEEnMzd # 5yiuJiuuDYZB4/GBYmW1Tr7PADY9GurNTMkGuSWfvl6dgr78qNoKs0T3wuJfb9oc # eQUMLF3Z/CXjuJKR1JHnuSXKd+Qv7bwt/Z5aGMMXMIIHWjCCBUKgAwIBAgITMwAA # AAX7elwyE2HfXQAAAAAABTANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQGEwJVUzEe # MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTQwMgYDVQQDEytNaWNyb3Nv # ZnQgSUQgVmVyaWZpZWQgQ29kZSBTaWduaW5nIFBDQSAyMDIxMB4XDTIxMDQxMzE3 # MzE1M1oXDTI2MDQxMzE3MzE1M1owWjELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjErMCkGA1UEAxMiTWljcm9zb2Z0IElEIFZlcmlm # aWVkIENTIEVPQyBDQSAwMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB # ANIamXw/MpCkwOgg21r7IZgaQ6AX+y79d9kVbkqlcEDt2gCy5LkZ50yKEZjBqNHy # DEK7cEelBwdOsXajpAH6gensbm10x7uOPnbh1AnROJ4IxCwUMpbjLkjpx2hHb3iG # 7d9ToTBF/+J0JKYePgIdHkeB9rE0a1Spiq5TqEJYYmu90INnR6IrXF9bk9b1typ6 # bfTLe+h+2R2yzbKTGS5FgWmyjJegXWlmV2KTxnUvqmPNIA2jQrxatHddFDLu8R3r # CKl6Uw090NwHjsUspUk3P++D96IPY9zrnphBWrhcy+ebdTL6WnRIUJg/LhTMRb/4 # mTo8L3HWNc4Wp1Sy8qZc9d/zc0qFN0I4T3agBoUSMIf2A86N4wnVSYFkEa1vNz96 # lhRZMTYjBNojuCLmII+0cLHhsL+yPXMTsmh4oSjHU/TXqEo6Ujc1ZyihnGDLTnTL # ShaqFewoptpvOBpiGGUwaK0fz6PYsJWrE2ChaRmanVismJyTthVfKDJlpCCtYmoC # y4BLemWkdK5P9Y1GLLMk4kalq/OELN1y/1eSlARLVBEH0P+EbZyNPbhRVCBiWVfZ # g/8TlJLFqHRqwkEnpuh8tutcTCQB6k6jLgyoMIvMZP5n5a+8oVzy+90jlC5rtQKr # uCOxqXukMDVtk7UAcTN77Uk5nT1uqyuctIBA+dUY7MitAgMBAAGjggIOMIICCjAO # BgNVHQ8BAf8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFGWfUc6F # aH8vikWIqt2nMbseDQBeMFQGA1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9y # eS5odG0wGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwEgYDVR0TAQH/BAgwBgEB # /wIBADAfBgNVHSMEGDAWgBTZQSmwDw9jbO9p1/XNKZ6kSGow5jBwBgNVHR8EaTBn # MGWgY6Bhhl9odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNy # b3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAy # MDIxLmNybDCBrgYIKwYBBQUHAQEEgaEwgZ4wbQYIKwYBBQUHMAKGYWh0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwSUQlMjBW # ZXJpZmllZCUyMENvZGUlMjBTaWduaW5nJTIwUENBJTIwMjAyMS5jcnQwLQYIKwYB # BQUHMAGGIWh0dHA6Ly9vbmVvY3NwLm1pY3Jvc29mdC5jb20vb2NzcDANBgkqhkiG # 9w0BAQwFAAOCAgEARUlg1HdPF+IOR871X6wdUolfKZOlzx0/Yz5Apr1P7rwc5mUQ # I2JNoCmEd6V6ErUSWif5YYwuQ6v9kez9WEWRwg2MitM70kTHROmELYBo5rHYcw9J # wkuoVVXIH5jULHDydVh8W7xuREIGENGRA9RTdDDj0M1ntc2x+VWtHUsbZ6HQVUY5 # 8g2BJu7DRHLyR0xt3l8wMndNBOSgwrBJeM+TtJr16sGh9j0tNtNBOj+Fqi8ILPzZ # lLufgGvC8P9hJ9lZCFuz5Iq+FJ9YxuvrY/3obqoBclDzwoepG575OPG4rIv8z4wF # ZI+6hK6+30mCAgsyeLOGFDVVR4HaBZ9sW1u2XwU90APc34avbuBMV261Q+a8V0kx # RFINoM0KvSR8bHR8jH3AiixUDlzg0s3GHi6Qnfq+hnKAwU6Mj3SnHIwupgKuvv4Y # jA56bylCB6cmBM1lHmrbcil7TH/kKyXkPp8uYwS/sanTjjxM93YO6p/P6Ka1K1Gx # iwb/X1ptfH1l3QL9TwrSy/2nDC7R6MnklTCkGKgx290JtLkPjUNGBOJFMUkGvlv3 # As2ACN9rjdJ2/TODK9aY+GyWYnTZDOCcmKns6ISC8WJIB226CUCEq0Fq5uUWHcoS # gaabSfSSZ9Gety43Z85TlMY5bAG0Iq9lps/ziRO9NwWx5kGUcMz8db7u0ucwggee # MIIFhqADAgECAhMzAAAAB4ejNKN7pY4cAAAAAAAHMA0GCSqGSIb3DQEBDAUAMHcx # CzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBG # BgNVBAMTP01pY3Jvc29mdCBJZGVudGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0 # aWZpY2F0ZSBBdXRob3JpdHkgMjAyMDAeFw0yMTA0MDEyMDA1MjBaFw0zNjA0MDEy # MDE1MjBaMGMxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y # YXRpb24xNDAyBgNVBAMTK01pY3Jvc29mdCBJRCBWZXJpZmllZCBDb2RlIFNpZ25p # bmcgUENBIDIwMjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCy8MCv # GYgo4t1UekxJbGkIVQm0Uv96SvjB6yUo92cXdylN65Xy96q2YpWCiTas7QPTkGnK # 9QMKDXB2ygS27EAIQZyAd+M8X+dmw6SDtzSZXyGkxP8a8Hi6EO9Zcwh5A+wOALNQ # bNO+iLvpgOnEM7GGB/wm5dYnMEOguua1OFfTUITVMIK8faxkP/4fPdEPCXYyy8NJ # 1fmskNhW5HduNqPZB/NkWbB9xxMqowAeWvPgHtpzyD3PLGVOmRO4ka0WcsEZqyg6 # efk3JiV/TEX39uNVGjgbODZhzspHvKFNU2K5MYfmHh4H1qObU4JKEjKGsqqA6Rzi # ybPqhvE74fEp4n1tiY9/ootdU0vPxRp4BGjQFq28nzawuvaCqUUF2PWxh+o5/TRC # b/cHhcYU8Mr8fTiS15kRmwFFzdVPZ3+JV3s5MulIf3II5FXeghlAH9CvicPhhP+V # aSFW3Da/azROdEm5sv+EUwhBrzqtxoYyE2wmuHKws00x4GGIx7NTWznOm6x/niqV # i7a/mxnnMvQq8EMse0vwX2CfqM7Le/smbRtsEeOtbnJBbtLfoAsC3TdAOnBbUkbU # fG78VRclsE7YDDBUbgWt75lDk53yi7C3n0WkHFU4EZ83i83abd9nHWCqfnYa9qIH # PqjOiuAgSOf4+FRcguEBXlD9mAInS7b6V0UaNwIDAQABo4ICNTCCAjEwDgYDVR0P # AQH/BAQDAgGGMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTZQSmwDw9jbO9p # 1/XNKZ6kSGow5jBUBgNVHSAETTBLMEkGBFUdIAAwQTA/BggrBgEFBQcCARYzaHR0 # cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRt # MBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMBAf8wHwYD # VR0jBBgwFoAUyH7SaoUqG8oZmAQHJ89QEE9oqKIwgYQGA1UdHwR9MHsweaB3oHWG # c2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy # MElkZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIwUm9vdCUyMENlcnRpZmljYXRlJTIw # QXV0aG9yaXR5JTIwMjAyMC5jcmwwgcMGCCsGAQUFBwEBBIG2MIGzMIGBBggrBgEF # BQcwAoZ1aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNy # b3NvZnQlMjBJZGVudGl0eSUyMFZlcmlmaWNhdGlvbiUyMFJvb3QlMjBDZXJ0aWZp # Y2F0ZSUyMEF1dGhvcml0eSUyMDIwMjAuY3J0MC0GCCsGAQUFBzABhiFodHRwOi8v # b25lb2NzcC5taWNyb3NvZnQuY29tL29jc3AwDQYJKoZIhvcNAQEMBQADggIBAH8l # Kp7+1Kvq3WYK21cjTLpebJDjW4ZbOX3HD5ZiG84vjsFXT0OB+eb+1TiJ55ns0BHl # uC6itMI2vnwc5wDW1ywdCq3TAmx0KWy7xulAP179qX6VSBNQkRXzReFyjvF2BGt6 # FvKFR/imR4CEESMAG8hSkPYso+GjlngM8JPn/ROUrTaeU/BRu/1RFESFVgK2wMz7 # fU4VTd8NXwGZBe/mFPZG6tWwkdmA/jLbp0kNUX7elxu2+HtHo0QO5gdiKF+YTYd1 # BGrmNG8sTURvn09jAhIUJfYNotn7OlThtfQjXqe0qrimgY4Vpoq2MgDW9ESUi1o4 # pzC1zTgIGtdJ/IvY6nqa80jFOTg5qzAiRNdsUvzVkoYP7bi4wLCj+ks2GftUct+f # GUxXMdBUv5sdr0qFPLPB0b8vq516slCfRwaktAxK1S40MCvFbbAXXpAZnU20FaAo # Dwqq/jwzwd8Wo2J83r7O3onQbDO9TyDStgaBNlHzMMQgl95nHBYMelLEHkUnVVVT # UsgC0Huj09duNfMaJ9ogxhPNThgq3i8w3DAGZ61AMeF0C1M+mU5eucj1Ijod5O2M # MPeJQ3/vKBtqGZg4eTtUHt/BPjN74SsJsyHqAdXVS5c+ItyKWg3Eforhox9k3Wgt # WTpgV4gkSiS4+A09roSdOI4vrRw+p+fL4WrxSK5nMYIXMjCCFy4CAQEwcTBaMQsw # CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSswKQYD # VQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ1MgRU9DIENBIDAyAhMzAAfM8rDv # Jyd7QZv4AAAAB8zyMA0GCWCGSAFlAwQCAQUAoF4wEAYKKwYBBAGCNwIBDDECMAAw # GQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwLwYJKoZIhvcNAQkEMSIEIF+wOaZ7 # io5/0IyanhWkcSysM7lV51IeaShZFn5T/Qf7MA0GCSqGSIb3DQEBAQUABIIBgDMa # vnTCQk2D/PcAOVknR3fpC+7w5GZGh5J5jZ9bMsIwrDb+CbJkt1DCuFpc8ePQtI/C # PTII2OX9R1PQ06kPbTNQBuSApGyZBzUQc+6tcYot93xoA8LP6SrggLyaYglQNpAi # gOp2qFpuWnZUtNuQhq8543hJw6iS7hdc25BB8k1T3d/n53HUvzhNFjREEQwmkBFT # WmUR3kfa0MiuKWB4ZQ+T5R645z3rKRte6i4GOOW2hKYs1o1Ul0EGU1QY2YlOnCZf # FSS4AdtmqY71h+7Lxtj24Z2EXTXZDICTqSsYv9uVXvqKk+I9V/jGBvIclJ2UwDa5 # +y1i3FA5L/VJ7J2CwpB86TdgMuZPOAh9z7PZXmYAzOT7vtfOp3rnKduZngynjcEt # ml99c1bCRLe/nt/vhVt2Z4HtXjsdyWCeoteYkxsVvYw2uk6qMpwtuMRWAmw9U389 # OlkwFeondZVjID8NDlMMN94XD1S8GTsuwV4flFwyIUngnE1nRjs5Gy6Iyh/yzqGC # FLIwghSuBgorBgEEAYI3AwMBMYIUnjCCFJoGCSqGSIb3DQEHAqCCFIswghSHAgED # MQ8wDQYJYIZIAWUDBAIBBQAwggFqBgsqhkiG9w0BCRABBKCCAVkEggFVMIIBUQIB # AQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUABCAppQo946siIrK36g1F8Kyn # bqD07iaNPJW6cOG7Xk8gtAIGacZcYMb4GBMyMDI2MDQwMzE0MzIyNi42MjdaMASA # AgH0oIHppIHmMIHjMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ # MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u # MS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQx # JzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo0NTFBLTA1RTAtRDk0NzE1MDMGA1UE # AxMsTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZSBTdGFtcGluZyBBdXRob3JpdHmg # gg8pMIIHgjCCBWqgAwIBAgITMwAAAAXlzw//Zi7JhwAAAAAABTANBgkqhkiG9w0B # AQwFADB3MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMUgwRgYDVQQDEz9NaWNyb3NvZnQgSWRlbnRpdHkgVmVyaWZpY2F0aW9uIFJv # b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMjAwHhcNMjAxMTE5MjAzMjMxWhcN # MzUxMTE5MjA0MjMxWjBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1l # c3RhbXBpbmcgQ0EgMjAyMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB # AJ5851Jj/eDFnwV9Y7UGIqMcHtfnlzPREwW9ZUZHd5HBXXBvf7KrQ5cMSqFSHGqg # 2/qJhYqOQxwuEQXG8kB41wsDJP5d0zmLYKAY8Zxv3lYkuLDsfMuIEqvGYOPURAH+ # Ybl4SJEESnt0MbPEoKdNihwM5xGv0rGofJ1qOYSTNcc55EbBT7uq3wx3mXhtVmtc # CEr5ZKTkKKE1CxZvNPWdGWJUPC6e4uRfWHIhZcgCsJ+sozf5EeH5KrlFnxpjKKTa # vwfFP6XaGZGWUG8TZaiTogRoAlqcevbiqioUz1Yt4FRK53P6ovnUfANjIgM9JDdJ # 4e0qiDRm5sOTiEQtBLGd9Vhd1MadxoGcHrRCsS5rO9yhv2fjJHrmlQ0EIXmp4DhD # BieKUGR+eZ4CNE3ctW4uvSDQVeSp9h1SaPV8UWEfyTxgGjOsRpeexIveR1MPTVf7 # gt8hY64XNPO6iyUGsEgt8c2PxF87E+CO7A28TpjNq5eLiiunhKbq0XbjkNoU5Jht # YUrlmAbpxRjb9tSreDdtACpm3rkpxp7AQndnI0Shu/fk1/rE3oWsDqMX3jjv40e8 # KN5YsJBnczyWB4JyeeFMW3JBfdeAKhzohFe8U5w9WuvcP1E8cIxLoKSDzCCBOu0h # WdjzKNu8Y5SwB1lt5dQhABYyzR3dxEO/T1K/BVF3rV69AgMBAAGjggIbMIICFzAO # BgNVHQ8BAf8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFGtpKDo1 # L0hjQM972K9J6T7ZPdshMFQGA1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9y # eS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUA # YgBDAEEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTIftJqhSobyhmYBAcn # z1AQT2ioojCBhAYDVR0fBH0wezB5oHegdYZzaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwSWRlbnRpdHklMjBWZXJpZmljYXRp # b24lMjBSb290JTIwQ2VydGlmaWNhdGUlMjBBdXRob3JpdHklMjAyMDIwLmNybDCB # lAYIKwYBBQUHAQEEgYcwgYQwgYEGCCsGAQUFBzAChnVodHRwOi8vd3d3Lm1pY3Jv # c29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMElkZW50aXR5JTIwVmVy # aWZpY2F0aW9uJTIwUm9vdCUyMENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAy # MC5jcnQwDQYJKoZIhvcNAQEMBQADggIBAF+Idsd+bbVaFXXnTHho+k7h2ESZJRWl # uLE0Oa/pO+4ge/XEizXvhs0Y7+KVYyb4nHlugBesnFqBGEdC2IWmtKMyS1OWIviw # pnK3aL5JedwzbeBF7POyg6IGG/XhhJ3UqWeWTO+Czb1c2NP5zyEh89F72u9UIw+I # fvM9lzDmc2O2END7MPnrcjWdQnrLn1Ntday7JSyrDvBdmgbNnCKNZPmhzoa8PccO # iQljjTW6GePe5sGFuRHzdFt8y+bN2neF7Zu8hTO1I64XNGqst8S+w+RUdie8fXC1 # jKu3m9KGIqF4aldrYBamyh3g4nJPj/LR2CBaLyD+2BuGZCVmoNR/dSpRCxlot0i7 # 9dKOChmoONqbMI8m04uLaEHAv4qwKHQ1vBzbV/nG89LDKbRSSvijmwJwxRxLLpMQ # /u4xXxFfR4f/gksSkbJp7oqLwliDm/h+w0aJ/U5ccnYhYb7vPKNMN+SZDWycU5OD # IRfyoGl59BsXR/HpRGtiJquOYGmvA/pk5vC1lcnbeMrcWD/26ozePQ/TWfNXKBOm # kFpvPE8CH+EeGGWzqTCjdAsno2jzTeNSxlx3glDGJgcdz5D/AAxw9Sdgq/+rY7jj # gs7X6fqPTXPmaCAJKVHAP19oEjJIBwD1LyHbaEgBxFCogYSOiUIr0Xqcr1nJfiWG # 2GwYe6ZoAF1bMIIHnzCCBYegAwIBAgITMwAAAFxhTACmp/LpIwAAAAAAXDANBgkq # hkiG9w0BAQwFADBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENv # cnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3Rh # bXBpbmcgQ0EgMjAyMDAeFw0yNjAxMDgxODU5MDZaFw0yNzAxMDcxODU5MDZaMIHj # MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk # bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRN # aWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5T # aGllbGQgVFNTIEVTTjo0NTFBLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0 # IFB1YmxpYyBSU0EgVGltZSBTdGFtcGluZyBBdXRob3JpdHkwggIiMA0GCSqGSIb3 # DQEBAQUAA4ICDwAwggIKAoICAQCuNYzOVXmTR3eDbVZVMTaDh6n+nv04Jw4zW6v7 # OTN1oTSxBIhyq6QKMBanA2eXpOyqQ0VvcXgcC5Sz3aMgldXyKR79bMIeLVPQtXSC # sjrrLjd9mpdd5VQq4HfKgaisPLFv6ynp1x2g1veINh5V+bLEFp1XCqWWCEd1KRMQ # pkUkLSFRBZaFmb6Nz3MGrRAmU4nxt0wIV/20wSlzhaFKalpP0hSwI+1sVCxN8H8r # lgh+0jGNZgCJEnXKw3SO/wJEjRhZMPaUSGEX7cwCrzqj/y1hnA+a8GbwfZ0lCQPm # Mrjbcvx3j1VL6VecFnpdhfyP5ApLH5CSkXtNYhiFi7mG889+Miz+Ccr7awPiFP1L # vAR9CTDZHz4ua/A5r4jOehH9AU7eEPxulAwy0BBywOl7tpK3gKMexwQygHFpZe5d # 7TPiuVzKwktbh9ro4CkDwcpdUHCRgysNOuZr8Wd60f9DLkiooQFRh/micZx82DUT # DlM5Ctcl4Ns4HejZNRGr+Gvd7V9kKuZF6XmW2td9qIZGL4eb515I0FUPRycH3vif # tPZVKYDbkh8G/4I84tmfPh4PacHu6JCdkC0BsOU0EZMP8Su2h9NmgwVzk86NVH7f # 1JhFcWwsxZxhRgI3K9EcH5xhWiMsqxebmZkrFighdqO7+yzozZZ3lkkqBWikYTg7 # ikY8PwIDAQABo4IByzCCAccwHQYDVR0OBBYEFK77MhyRGGREOW504FoDEie6JOdp # MB8GA1UdIwQYMBaAFGtpKDo1L0hjQM972K9J6T7ZPdshMGwGA1UdHwRlMGMwYaBf # oF2GW2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29m # dCUyMFB1YmxpYyUyMFJTQSUyMFRpbWVzdGFtcGluZyUyMENBJTIwMjAyMC5jcmww # eQYIKwYBBQUHAQEEbTBrMGkGCCsGAQUFBzAChl1odHRwOi8vd3d3Lm1pY3Jvc29m # dC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFB1YmxpYyUyMFJTQSUyMFRp # bWVzdGFtcGluZyUyMENBJTIwMjAyMC5jcnQwDAYDVR0TAQH/BAIwADAWBgNVHSUB # Af8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8EBAMCB4AwZgYDVR0gBF8wXTBRBgwr # BgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMAgGBmeBDAEEAjANBgkqhkiG # 9w0BAQwFAAOCAgEAhXbQN9yxJIQFnYCFueVeZ09WRv1WkODNsgQQ7iClH9tHz1tD # 6pbi0LT3KHa1xmQ3gojjdzqd5FE1wGMAaZvu2DzKyW0ZWYDED7BbW0nRwvWxE9DS # VfKFwxhFgTkHu5cMB9Ofj2te8Qdv5plXp1lra2V9dSPAaBY3D9g8GUieV9Ruk03u # hmCZffR+fIobO07/0xGT+3PJo+nlXjgrIsihl6UU2CS/cpbbenCinHJnK2lUozE7 # +N25qSyy9Vgqvsv09xxLY14syl0aOZt0xOvVIIqLKmeui3h9HbxQfbtfgexLQ40z # 7wsnOJ/N/lt75vQaswZr39xEoMLeCeShyvgqMionmkQXT961Ti6LpNzGhZABR7YV # pX+q84f9A6Kbl8amG8txKLdXOd9DKkCd9b+9sSTEnuULPsyuearCoNtr3JOm9psI # Q/2TYeumHgbFWNpEvWoZBjLUfjoD89A5w4vjnketG8ImRyYn8MhzE3Brk/aVJ6e5 # wrentLyIYbZidbZRCDLq1uEmLVColC8z+ki3avMrNfgVKIQobf7YIvom1n00p6O7 # 3gQu8WiYuibJKgPxPD3RM1Dlh2m8GIkh15WTG6Gzk0dA5NyM2qoFFF/hNsbH5lY9 # qLrYb1meeXNfz3yytaeMs0Xvfq2N1eDYtDkRlEFoXn4JDWLKQdY2Ylw6vIMxggPU # MIID0AIBATB4MGExCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWVzdGFt # cGluZyBDQSAyMDIwAhMzAAAAXGFMAKan8ukjAAAAAABcMA0GCWCGSAFlAwQCAQUA # oIIBLTAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIE # IKy6oA+6Cad5DT8GT1Rn2SX4+Hwyd5Ja7AG72jH6axftMIHdBgsqhkiG9w0BCRAC # LzGBzTCByjCBxzCBoAQg97pqQYd3bjD5LeiLZCbTs0cAUbdUPCOdd6vJa36g7tww # fDBlpGMwYTELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh # dGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZXN0YW1waW5n # IENBIDIwMjACEzMAAABcYUwApqfy6SMAAAAAAFwwIgQgGQuCwkvLVvw2lkXkhN/p # i290+nUKte06wfuwlK+w8BowDQYJKoZIhvcNAQELBQAEggIATjzgsad8sZCl7Gsn # Jytby30Wi3vX/GxlSz4VS+6jHaHQnda5irESi1Xyn7UTWR3lPzz8Lvu5F599s9HL # ULucBSuBFprBPXQYdYqOO0AEOZsd+t1NdoeVz9jYiJXBLKG1nXnqd/jIy1AdwzXk # 7/y20QrU+e8Oq4ppwNf1Im5CF/8xqa/yLJwAC37djA1cvY7KWUu8ubjnb6eAbvRm # 1ltdwg++zQH/pS8Ewrop9NZTpVWfOPUtfZ1JraglaI6KgVm5rPjzhnoRJP0ExwV5 # XwedJ4S9Gv3JfZ/cX4A+tmJYbw1leh5UeUoDQkJNWfXKwRVmq5tT6ToaYKBCvt3V # BCAxPfmPTUDBZ/XwIZOfARU8DF+qOXz4kpYDEexjWSBwJq7U/0qyDo0e95j8vOwL # oEr8GV3+ko//tsq7rYCauUS9KbDBplqJ20Khxqb/ruP55SnPakNJPffLfYP01h2M # /SupLj9mzKkYAt9iUHSRlHup58lvDaUANa8hMM/mFdR+qLB8v9hSLVmPr4x6hLFy # 7KhKM5G/yatNq2Hb8nfzVYt1cJs3ep1GN3EBu2K8/DIXx2JRsT6cKUMVfbrTFccV # zR3qaagTyziYGLhWwzjsufOQ0ARRcTZhZPNRU8T1tdr0ZjPY2Qq8F9+HG/r31Kud # cHpvlX2njAEnopgL5Ok1axbxHUs= # SIG # End signature block |