helpers/discovery/DiscoveryProvider-VMware.ps1
|
<#
.SYNOPSIS VMware vSphere discovery provider for infrastructure monitoring. .DESCRIPTION Registers a VMware discovery provider that discovers ESXi hosts and virtual machines, then builds a monitor plan suitable for WhatsUp Gold REST API monitors or standalone use. Two collection methods: [1] VMware PowerCLI -- uses Connect-VIServer, Get-VMHost, Get-VM, etc. [2] REST API direct -- zero external dependencies, uses vCenter REST API The method is selected by the caller via Credential.UseRestApi = $true/$false. Discovery discovers: - ESXi hosts (IP, CPU, Memory, Storage, Version, Power State) - Virtual machines (IP, CPU, Memory, Guest OS, Tools Status) Authentication: PSCredential (username + password) stored in DPAPI vault. For WUG monitors, each device can be polled via standard SNMP/WMI or via custom REST API monitors pointing at vCenter API. Prerequisites: Module mode: VMware PowerCLI installed REST mode: No external dependencies (vSphere 6.5+ required) .NOTES Author: Jason Alberino (jason@wug.ninja) Requires: DiscoveryHelpers.ps1 loaded first Encoding: UTF-8 with BOM #> # Ensure DiscoveryHelpers is available if (-not (Get-Command -Name 'Register-DiscoveryProvider' -ErrorAction SilentlyContinue)) { $discoveryPath = Join-Path (Split-Path $MyInvocation.MyCommand.Path -Parent) 'DiscoveryHelpers.ps1' if (Test-Path $discoveryPath) { . $discoveryPath } else { throw "DiscoveryHelpers.ps1 not found. Load it before this provider." } } # Ensure VMwareHelpers is available $vmwareHelpersPath = Join-Path (Split-Path $MyInvocation.MyCommand.Path -Parent) '..\vmware\VMwareHelpers.ps1' if (Test-Path $vmwareHelpersPath) { . $vmwareHelpersPath } # ============================================================================ # VMware Discovery Provider # ============================================================================ Register-DiscoveryProvider -Name 'VMware' ` -MatchAttribute 'DiscoveryHelper.VMware' ` -AuthType 'BasicAuth' ` -DefaultPort 443 ` -DefaultProtocol 'https' ` -IgnoreCertErrors $true ` -DiscoverScript { param($ctx) $items = @() $deviceIP = $ctx.DeviceIP $ignoreCert = if ($ctx.IgnoreCertErrors) { '1' } else { '0' } # --- Resolve credential --- $cred = $null if ($ctx.Credential -and $ctx.Credential.PSCredential -and $ctx.Credential.PSCredential -is [PSCredential]) { $cred = $ctx.Credential.PSCredential } elseif ($ctx.Credential -and $ctx.Credential.Username -and $ctx.Credential.Password) { $secPwd = ConvertTo-SecureString $ctx.Credential.Password -AsPlainText -Force $cred = [PSCredential]::new($ctx.Credential.Username, $secPwd) } elseif ($ctx.Credential -and $ctx.Credential -is [PSCredential]) { $cred = $ctx.Credential } if (-not $cred) { Write-Warning "No valid VMware credential available." return $items } # Determine collection method $useRest = $false if ($ctx.Credential -and $ctx.Credential.UseRestApi) { $useRest = $ctx.Credential.UseRestApi } # ================================================================ # Phase 1: Connect and enumerate # ================================================================ $hostMap = @{} # hostName -> @{ IP; Cluster; PowerState; Version; Build; ... } $vmMap = @{} # vmName -> @{ IP; ESXiHost; PowerState; GuestOS; ... } if ($useRest) { # --- REST API mode --- try { Write-Host " Connecting to vCenter REST API at $deviceIP..." -ForegroundColor DarkGray $connParams = @{ Server = $deviceIP Credential = $cred Port = $ctx.Port IgnoreSSLErrors = ($ignoreCert -eq '1') } Connect-VMwareREST @connParams Write-Host " Connected to vCenter REST API." -ForegroundColor DarkGray } catch { Write-Warning "Failed to connect to VMware REST API $deviceIP : $_" return $items } try { # ---------------------------------------------------------- # Step 1: Enumerate ESXi hosts # ---------------------------------------------------------- Write-Host " Enumerating ESXi hosts..." -ForegroundColor DarkGray $esxiHosts = @(Get-VMwareHostsREST) Write-Host " Found $($esxiHosts.Count) ESXi host(s)." -ForegroundColor DarkGray # Build hostId -> hostName lookup $hostIdToName = @{} foreach ($esxi in $esxiHosts) { $hostIdToName[$esxi.HostId] = $esxi.Name } # ---------------------------------------------------------- # Step 2: Resolve cluster-to-host membership # ---------------------------------------------------------- Write-Host " Resolving cluster membership..." -ForegroundColor DarkGray $clusterHostMap = @{} # hostName -> clusterName try { $clusters = @(Get-VMwareClustersREST) foreach ($c in $clusters) { try { $cHosts = @(Invoke-VMwareREST -Path "/api/vcenter/host?clusters=$($c.ClusterId)") foreach ($ch in $cHosts) { $hName = "$($ch.name)" if ($hName) { $clusterHostMap[$hName] = "$($c.Name)" } } } catch { } } Write-Host " Found $($clusters.Count) cluster(s)." -ForegroundColor DarkGray } catch { Write-Host " No cluster info available." -ForegroundColor DarkGray } # ---------------------------------------------------------- # Step 3: Build host entries with cluster + DNS IP # ---------------------------------------------------------- foreach ($esxi in $esxiHosts) { Write-Host " Host: $($esxi.Name)" -ForegroundColor DarkGray # Resolve management IP via DNS $mgmtIP = $null try { $resolved = [System.Net.Dns]::GetHostAddresses($esxi.Name) | Where-Object { $_.AddressFamily -eq 'InterNetwork' } | Select-Object -First 1 if ($resolved) { $mgmtIP = $resolved.IPAddressToString } } catch { } $clusterName = if ($clusterHostMap.ContainsKey($esxi.Name)) { $clusterHostMap[$esxi.Name] } else { 'N/A' } $hostMap[$esxi.Name] = @{ IP = $mgmtIP Cluster = $clusterName PowerState = "$($esxi.PowerState)" Version = 'N/A' Build = 'N/A' CpuSockets = 'N/A' CpuCores = 'N/A' MemTotalGB = 'N/A' Manufacturer= 'N/A' Model = 'N/A' } } # ---------------------------------------------------------- # Step 4: Build VM-to-host mapping (query VMs per host) # ---------------------------------------------------------- Write-Host " Mapping VMs to ESXi hosts..." -ForegroundColor DarkGray $vmIdToHost = @{} # vmMoRef -> hostName foreach ($esxi in $esxiHosts) { try { $hostVMs = @(Invoke-VMwareREST -Path "/api/vcenter/vm?hosts=$($esxi.HostId)") foreach ($hv in $hostVMs) { $vmIdToHost["$($hv.vm)"] = $esxi.Name } Write-Host " $($esxi.Name): $($hostVMs.Count) VM(s)" -ForegroundColor DarkGray } catch { Write-Host " $($esxi.Name): error querying VMs" -ForegroundColor DarkYellow } } # ---------------------------------------------------------- # Step 5: Discover VMs with full details # ---------------------------------------------------------- Write-Host " Enumerating VMs..." -ForegroundColor DarkGray $allVMs = @(Get-VMwareVMsREST) $vmTotal = $allVMs.Count Write-Host " Found $vmTotal VM(s). Resolving details (this may take a while)..." -ForegroundColor DarkGray $vmCount = 0 foreach ($vm in $allVMs) { $vmCount++ if ($vmCount % 50 -eq 0 -or $vmCount -eq $vmTotal) { Write-Host " VM $vmCount / $vmTotal ..." -ForegroundColor DarkGray } $vmDetail = Get-VMwareVMDetailREST -VMId $vm.VMId -VMName $vm.Name $vmIP = $vmDetail.IPAddress if (-not $vmIP) { $vmIP = $null } # Look up host + cluster from our mappings $vmHostName = if ($vmIdToHost.ContainsKey($vm.VMId)) { $vmIdToHost[$vm.VMId] } else { 'N/A' } $vmCluster = if ($vmHostName -ne 'N/A' -and $clusterHostMap.ContainsKey($vmHostName)) { $clusterHostMap[$vmHostName] } else { 'N/A' } $vmMap[$vm.Name] = @{ IP = $vmIP ESXiHost = $vmHostName Cluster = $vmCluster PowerState = "$($vmDetail.PowerState)" GuestOS = "$($vmDetail.GuestOS)" ToolsStatus= "$($vmDetail.ToolsStatus)" NumCPU = "$($vmDetail.NumCPU)" MemoryGB = "$($vmDetail.MemoryGB)" DiskCount = "$($vmDetail.DiskCount)" NicCount = "$($vmDetail.NicCount)" } } } catch { Write-Warning "Error during VMware REST enumeration: $_" } finally { Write-Host " Disconnecting from vCenter REST API..." -ForegroundColor DarkGray try { Disconnect-VMwareREST } catch { } } } else { # --- PowerCLI module mode --- try { $connParams = @{ Server = $deviceIP Credential = $cred Port = $ctx.Port } if ($ignoreCert -eq '1') { Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false -Scope Session -ErrorAction SilentlyContinue | Out-Null } $viConn = Connect-VIServer @connParams -ErrorAction Stop Write-Verbose "Connected to VMware: $deviceIP ($($viConn.ProductLine) $($viConn.Version))" } catch { Write-Warning "Failed to connect to VMware $deviceIP : $_" return $items } try { # Discover ESXi hosts $esxiHosts = Get-VMHost -ErrorAction Stop foreach ($esxi in $esxiHosts) { $mgmtIP = $null try { $mgmtIP = (Get-VMHostNetworkAdapter -VMHost $esxi -VMKernel -ErrorAction SilentlyContinue | Where-Object { $_.ManagementTrafficEnabled } | Select-Object -First 1).IP } catch { } if (-not $mgmtIP) { $mgmtIP = $null } $clusterName = if ($esxi.Parent -and $esxi.Parent.GetType().Name -eq 'ClusterImpl') { "$($esxi.Parent.Name)" } else { 'N/A' } $hostMap[$esxi.Name] = @{ IP = $mgmtIP Cluster = $clusterName PowerState = "$($esxi.PowerState)" Version = "$($esxi.Version)" Build = "$($esxi.Build)" CpuSockets = "$($esxi.ExtensionData.Hardware.CpuInfo.NumCpuPackages)" CpuCores = "$($esxi.ExtensionData.Hardware.CpuInfo.NumCpuCores)" MemTotalGB = "$([math]::Round($esxi.MemoryTotalGB, 2))" Manufacturer= "$($esxi.Manufacturer)" Model = "$($esxi.Model)" } } # Discover VMs $allVMs = Get-VM -ErrorAction Stop foreach ($vm in $allVMs) { $vmIP = $null try { $guest = $vm | Get-VMGuest -ErrorAction SilentlyContinue $vmIP = $guest.IPAddress | Where-Object { $_ -match '^\d{1,3}(\.\d{1,3}){3}$' } | Select-Object -First 1 } catch { } $vmHost = "$($vm.VMHost.Name)" $clusterName = if ($vm.VMHost.Parent -and $vm.VMHost.Parent.GetType().Name -eq 'ClusterImpl') { "$($vm.VMHost.Parent.Name)" } else { 'N/A' } $vmMap[$vm.Name] = @{ IP = $vmIP ESXiHost = $vmHost Cluster = $clusterName PowerState = "$($vm.PowerState)" GuestOS = "$($vm.ExtensionData.Config.GuestFullName)" ToolsStatus= "$($vm.ExtensionData.Guest.ToolsStatus)" NumCPU = "$($vm.NumCpu)" MemoryGB = "$($vm.MemoryGB)" DiskCount = "$(@($vm | Get-HardDisk -ErrorAction SilentlyContinue).Count)" NicCount = "$(@($vm | Get-NetworkAdapter -ErrorAction SilentlyContinue).Count)" } } } catch { Write-Warning "Error during VMware enumeration: $_" } finally { try { Disconnect-VIServer -Server $deviceIP -Confirm:$false -ErrorAction SilentlyContinue } catch { } } } Write-Host " Topology: $($hostMap.Count) ESXi host(s), $($vmMap.Count) VM(s)" -ForegroundColor DarkGray # ================================================================ # Phase 2: Build discovery plan # ================================================================ $baseAttrs = @{ 'VMware.vCenter' = $deviceIP 'VMware.Port' = [string]$ctx.Port 'DiscoveryHelper.VMware' = 'true' 'DiscoveryHelper.VMware.LastRun' = (Get-Date).ToUniversalTime().ToString('o') } # --- vCenter device (the API entry point) --- $vcAttrs = $baseAttrs.Clone() $vcAttrs['VMware.DeviceType'] = 'vCenter' $items += New-DiscoveredItem ` -Name 'VMware - vCenter Status' ` -ItemType 'ActiveMonitor' ` -MonitorType 'PowerShell' ` -MonitorParams @{ Description = 'Monitors vCenter connectivity and service health' } ` -UniqueKey "VMware:vcenter:active:status" ` -Attributes $vcAttrs ` -Tags @('vmware', 'vcenter') # --- Per-Host items --- foreach ($hostName in @($hostMap.Keys | Sort-Object)) { $hostInfo = $hostMap[$hostName] $hostIP = $hostInfo.IP $hostAttrs = $baseAttrs.Clone() $hostAttrs['VMware.DeviceType'] = 'ESXiHost' $hostAttrs['VMware.HostName'] = $hostName $hostAttrs['VMware.Cluster'] = $hostInfo.Cluster $hostAttrs['VMware.PowerState'] = $hostInfo.PowerState $hostAttrs['VMware.Version'] = $hostInfo.Version $hostAttrs['VMware.Build'] = $hostInfo.Build if ($hostIP) { $hostAttrs['VMware.HostIP'] = $hostIP } $items += New-DiscoveredItem ` -Name 'VMware - ESXi Host Status' ` -ItemType 'ActiveMonitor' ` -MonitorType 'PowerShell' ` -MonitorParams @{ Description = "Monitors ESXi host $hostName connectivity" } ` -UniqueKey "VMware:host:${hostName}:active:status" ` -Attributes $hostAttrs ` -Tags @('vmware', 'esxi', $hostName, $(if ($hostIP) { $hostIP } else { 'no-ip' })) $hostPerfMonitors = @( @{ Name = 'VMware - Host CPU'; Key = 'cpu' } @{ Name = 'VMware - Host Memory'; Key = 'memory' } @{ Name = 'VMware - Host Network'; Key = 'network' } @{ Name = 'VMware - Host Disk'; Key = 'disk' } ) foreach ($pm in $hostPerfMonitors) { $items += New-DiscoveredItem ` -Name $pm.Name ` -ItemType 'PerformanceMonitor' ` -MonitorType 'PowerShell' ` -MonitorParams @{ Description = "$($pm.Name) for host $hostName" } ` -UniqueKey "VMware:host:${hostName}:perf:$($pm.Key)" ` -Attributes $hostAttrs ` -Tags @('vmware', 'esxi', $hostName, $(if ($hostIP) { $hostIP } else { 'no-ip' })) } } # --- Per-VM items --- foreach ($vmName in @($vmMap.Keys | Sort-Object)) { $vmInfo = $vmMap[$vmName] $vmIP = $vmInfo.IP $vmAttrs = $baseAttrs.Clone() $vmAttrs['VMware.DeviceType'] = 'VM' $vmAttrs['VMware.VMName'] = $vmName $vmAttrs['VMware.ESXiHost'] = $vmInfo.ESXiHost $vmAttrs['VMware.Cluster'] = $vmInfo.Cluster $vmAttrs['VMware.PowerState'] = $vmInfo.PowerState $vmAttrs['VMware.GuestOS'] = $vmInfo.GuestOS $vmAttrs['VMware.ToolsStatus'] = $vmInfo.ToolsStatus $vmAttrs['VMware.NumCPU'] = $vmInfo.NumCPU $vmAttrs['VMware.MemoryGB'] = $vmInfo.MemoryGB if ($vmInfo.DiskCount) { $vmAttrs['VMware.DiskCount'] = $vmInfo.DiskCount } if ($vmInfo.NicCount) { $vmAttrs['VMware.NicCount'] = $vmInfo.NicCount } if ($vmIP) { $vmAttrs['VMware.VMIP'] = $vmIP } $items += New-DiscoveredItem ` -Name 'VMware - VM Status' ` -ItemType 'ActiveMonitor' ` -MonitorType 'PowerShell' ` -MonitorParams @{ Description = "Monitors VM $vmName power state" } ` -UniqueKey "VMware:vm:${vmName}:active:status" ` -Attributes $vmAttrs ` -Tags @('vmware', 'vm', $vmName, $(if ($vmIP) { $vmIP } else { 'no-ip' }), $vmInfo.ESXiHost) $vmPerfMonitors = @( @{ Name = 'VMware - VM CPU'; Key = 'cpu' } @{ Name = 'VMware - VM Memory'; Key = 'memory' } @{ Name = 'VMware - VM Network'; Key = 'network' } @{ Name = 'VMware - VM Disk'; Key = 'disk' } ) foreach ($pm in $vmPerfMonitors) { $items += New-DiscoveredItem ` -Name $pm.Name ` -ItemType 'PerformanceMonitor' ` -MonitorType 'PowerShell' ` -MonitorParams @{ Description = "$($pm.Name) for VM $vmName" } ` -UniqueKey "VMware:vm:${vmName}:perf:$($pm.Key)" ` -Attributes $vmAttrs ` -Tags @('vmware', 'vm', $vmName, $(if ($vmIP) { $vmIP } else { 'no-ip' }), $vmInfo.ESXiHost) } } $cred = $null; $secPwd = $null return $items } # ============================================================================== # Export-VMwareDiscoveryDashboardHtml # ============================================================================== function Export-VMwareDiscoveryDashboardHtml { <# .SYNOPSIS Generates a VMware dashboard HTML file from live vSphere data. .DESCRIPTION Reads the VMware dashboard template from the discovery directory, injects column definitions and row data as JSON, and writes the final HTML to OutputPath. Uses the same template as the standalone VMware dashboard but sourced from the discovery folder. .PARAMETER DashboardData Array of PSCustomObject rows — one per host or VM. .PARAMETER OutputPath File path for the generated HTML. .PARAMETER ReportTitle Dashboard title shown in header and browser tab. .PARAMETER TemplatePath Path to VMware-Dashboard-Template.html. Defaults to same directory. #> [CmdletBinding()] param( [Parameter(Mandatory)]$DashboardData, [Parameter(Mandatory)][string]$OutputPath, [string]$ReportTitle = 'VMware vSphere Dashboard', [string]$TemplatePath ) if (-not $TemplatePath) { $TemplatePath = Join-Path $PSScriptRoot 'VMware-Dashboard-Template.html' if (-not (Test-Path $TemplatePath)) { $TemplatePath = Join-Path (Split-Path $PSScriptRoot -Parent) 'vmware\VMware-Dashboard-Template.html' } } if (-not (Test-Path $TemplatePath)) { Write-Error "Template not found: $TemplatePath" return } $titleMap = @{ 'Type' = 'Type' 'Name' = 'Name' 'PowerState' = 'Power State' 'IPAddress' = 'IP Address' 'Cluster' = 'Cluster' 'ESXiHost' = 'ESXi Host' 'GuestOS' = 'Guest OS' 'ToolsStatus' = 'Tools Status' 'CPU' = 'CPU' 'Memory' = 'Memory' 'CpuUsagePct' = 'CPU %' 'MemUsagePct' = 'Mem %' 'NetUsageKBps' = 'Net KBps' 'DiskUsageKBps' = 'Disk KBps' 'Hardware' = 'Hardware' 'VersionBuild' = 'Version / Build' 'Datastores' = 'Datastores' 'ProvisionedSpaceGB' = 'Provisioned GB' 'UsedSpaceGB' = 'Used GB' 'NicCount' = 'NICs' 'DiskCount' = 'Disks' 'DiskLatencyMs' = 'Disk Latency ms' } $firstObj = $DashboardData | Select-Object -First 1 $columns = @() foreach ($prop in $firstObj.PSObject.Properties) { $title = if ($titleMap.ContainsKey($prop.Name)) { $titleMap[$prop.Name] } else { ($prop.Name -creplace '(?<=[a-z])([A-Z])', ' $1').Trim() } $col = @{ field = $prop.Name title = $title sortable = $true searchable = $true } if ($prop.Name -eq 'PowerState') { $col.formatter = 'formatPowerState' } if ($prop.Name -eq 'ToolsStatus') { $col.formatter = 'formatToolsStatus' } if ($prop.Name -eq 'Type') { $col.formatter = 'formatType' } $columns += $col } $columnsJson = $columns | ConvertTo-Json -Depth 5 -Compress $dataJson = ConvertTo-Json -InputObject @($DashboardData) -Depth 5 -Compress $tableConfig = @" columns: $columnsJson, data: $dataJson "@ $html = Get-Content -Path $TemplatePath -Raw $html = $html -replace 'replaceThisHere', $tableConfig $html = $html -replace 'ReplaceYourReportNameHere', $ReportTitle $html = $html -replace 'ReplaceUpdateTimeHere', (Get-Date).ToString('yyyy-MM-dd HH:mm:ss') $parentDir = Split-Path $OutputPath -Parent if ($parentDir -and -not (Test-Path $parentDir)) { New-Item -ItemType Directory -Path $parentDir -Force | Out-Null } Set-Content -Path $OutputPath -Value $html -Encoding UTF8 Write-Verbose "Dashboard written to: $OutputPath" return $OutputPath } # SIG # Begin signature block # MIIr+wYJKoZIhvcNAQcCoIIr7DCCK+gCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDQN9prstfYTljB # Uojn/nVAeMUuRLBdQNM+g/XNAc3eVqCCJQ0wggVvMIIEV6ADAgECAhBI/JO0YFWU # jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI # DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM # EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy # dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG # EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv # IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s # hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD # J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7 # P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme # me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz # T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q # RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz # mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc # QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T # OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/ # AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID # AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD # VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV # HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE # VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v # ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE # KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI # hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF # OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC # J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ # pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl # d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH # +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggWNMIIEdaADAgECAhAOmxiO # +dAt5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYD # VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAi # BgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAw # MDBaFw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERp # Z2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC # AgoCggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsb # hA3EMB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iT # cMKyunWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGb # NOsFxl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclP # XuU15zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCr # VYJBMtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFP # ObURWBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTv # kpI6nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWM # cCxBYKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls # 5Q5SUUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBR # a2+xq4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6 # MIIBNjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qY # rhwPTzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8E # BAMCAYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k # aWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0 # LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDig # NoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCg # v0NcVec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQT # SnovLbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh # 65ZyoUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSw # uKFWjuyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAO # QGPFmCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjD # TZ9ztwGpn1eqXijiuZQwggYaMIIEAqADAgECAhBiHW0MUgGeO5B5FSCJIRwKMA0G # CSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExp # bWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBSb290 # IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5NTlaMFQxCzAJBgNVBAYT # AkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28g # UHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0GCSqGSIb3DQEBAQUAA4IB # jwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjIztNsfvxYB5UXeWUzCxEe # AEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NVDgFigOMYzB2OKhdqfWGV # oYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/36F09fy1tsB8je/RV0mIk # 8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05ZwmRmTnAO5/arnY83jeNzh # P06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm+qxp4VqpB3MV/h53yl41 # aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUedyz8rNyfQJy/aOs5b4s+ # ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz44MPZ1f9+YEQIQty/NQd/ # 2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBMdlyh2n5HirY4jKnFH/9g # Rvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQYMBaAFDLrkpr/NZZILyhA # QnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritUpimqF6TNDDAOBgNVHQ8B # Af8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNVHSUEDDAKBggrBgEFBQcD # AzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsGA1UdHwREMEIwQKA+oDyG # Omh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5n # Um9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsGAQUFBzAChjpodHRwOi8v # Y3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ1Jvb3RSNDYu # cDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG # 9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURhw1aVcdGRP4Wh60BAscjW # 4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0ZdOaWTsyNyBBsMLHqafvIh # rCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajjcw5+w/KeFvPYfLF/ldYp # mlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNcWbWDRF/3sBp6fWXhz7Dc # ML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalOhOfCipnx8CaLZeVme5yE # Lg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJszkyeiaerlphwoKx1uHRz # NyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z76mKnzAfZxCl/3dq3dUNw # 4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5JKdGvspbOrTfOXyXvmPL6 # E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHHj95Ejza63zdrEcxWLDX6 # xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2Bev6SivBBOHY+uqiirZt # g0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/L9Uo2bC5a4CH2RwwggY+ # MIIEpqADAgECAhAHnODk0RR/hc05c892LTfrMA0GCSqGSIb3DQEBDAUAMFQxCzAJ # BgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNl # Y3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwHhcNMjYwMjA5MDAwMDAw # WhcNMjkwNDIxMjM1OTU5WjBVMQswCQYDVQQGEwJVUzEUMBIGA1UECAwLQ29ubmVj # dGljdXQxFzAVBgNVBAoMDkphc29uIEFsYmVyaW5vMRcwFQYDVQQDDA5KYXNvbiBB # bGJlcmlubzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPN6aN4B1yYW # kI5b5TBj3I0VV/peETrHb6EY4BHGxt8Ap+eT+WpEpJyEtRYPxEmNJL3A38Bkg7mw # zPE3/1NK570ZBCuBjSAn4mSDIgIuXZnvyBO9W1OQs5d67MlJLUAEufl18tOr3ST1 # DeO9gSjQSAE5Nql0QDxPnm93OZBon+Fz3CmE+z3MwAe2h4KdtRAnCqwM+/V7iBdb # w+JOxolpx+7RVjGyProTENIG3pe/hKvPb501lf8uBAADLdjZr5ip8vIWbf857Yw1 # Bu10nVI7HW3eE8Cl5//d1ribHlzTzQLfttW+k+DaFsKZBBL56l4YAlIVRsrOiE1k # dHYYx6IGrEA809R7+TZA9DzGqyFiv9qmJAbL4fDwetDeyIq+Oztz1LvEdy8Rcd0J # BY+J4S0eDEFIA3X0N8VcLeAwabKb9AjulKXwUeqCJLvN79CJ90UTZb2+I+tamj0d # n+IKMEsJ4v4Ggx72sxFr9+6XziodtTg5Luf2xd6+PhhamOxF2px9LObhBLLEMyRs # CHZIzVZOFKu9BpHQH7ufGB+Sa80Tli0/6LEyn9+bMYWi2ttn6lLOPThXMiQaooRU # q6q2u3+F4SaPlxVFLI7OJVMhar6nW6joBvELTJPmANSMjDSRFDfHRCdGbZsL/keE # LJNy+jZctF6VvxQEjFM8/bazu6qYhrA7AgMBAAGjggGJMIIBhTAfBgNVHSMEGDAW # gBQPKssghyi47G9IritUpimqF6TNDDAdBgNVHQ4EFgQU6YF0o0D5AVhKHbVocr8G # aSIBibAwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYI # KwYBBQUHAwMwSgYDVR0gBEMwQTA1BgwrBgEEAbIxAQIBAwIwJTAjBggrBgEFBQcC # ARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQBMEkGA1UdHwRCMEAw # PqA8oDqGOGh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVT # aWduaW5nQ0FSMzYuY3JsMHkGCCsGAQUFBwEBBG0wazBEBggrBgEFBQcwAoY4aHR0 # cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIz # Ni5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqG # SIb3DQEBDAUAA4IBgQAEIsm4xnOd/tZMVrKwi3doAXvCwOA/RYQnFJD7R/bSQRu3 # wXEK4o9SIefye18B/q4fhBkhNAJuEvTQAGfqbbpxow03J5PrDTp1WPCWbXKX8Oz9 # vGWJFyJxRGftkdzZ57JE00synEMS8XCwLO9P32MyR9Z9URrpiLPJ9rQjfHMb1BUd # vaNayomm7aWLAnD+X7jm6o8sNT5An1cwEAob7obWDM6sX93wphwJNBJAstH9Ozs6 # LwISOX6sKS7CKm9N3Kp8hOUue0ZHAtZdFl6o5u12wy+zzieGEI50fKnN77FfNKFO # WKlS6OJwlArcbFegB5K89LcE5iNSmaM3VMB2ADV1FEcjGSHw4lTg1Wx+WMAMdl/7 # nbvfFxJ9uu5tNiT54B0s+lZO/HztwXYQUczdsFon3pjsNrsk9ZlalBi5SHkIu+F6 # g7tWiEv3rtVApmJRnLkUr2Xq2a4nbslUCt4jKs5UX4V1nSX8OM++AXoyVGO+iTj7 # z+pl6XE9Gw/Td6WKKKswgga0MIIEnKADAgECAhANx6xXBf8hmS5AQyIMOkmGMA0G # CSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAwMDBaFw0zODAxMTQyMzU5NTla # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEy # NTYgMjAyNSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0eDHT # CphBcr48RsAcrHXbo0ZodLRRF51NrY0NlLWZloMsVO1DahGPNRcybEKq+RuwOnPh # of6pvF4uGjwjqNjfEvUi6wuim5bap+0lgloM2zX4kftn5B1IpYzTqpyFQ/4Bt0mA # xAHeHYNnQxqXmRinvuNgxVBdJkf77S2uPoCj7GH8BLuxBG5AvftBdsOECS1UkxBv # MgEdgkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2Ws3IfDReb6e3mmdglTcaarps # 0wjUjsZvkgFkriK9tUKJm/s80FiocSk1VYLZlDwFt+cVFBURJg6zMUjZa/zbCclF # 83bRVFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9oHRaQT/aofEnS5xLrfxnGpTXi # UOeSLsJygoLPp66bkDX1ZlAeSpQl92QOMeRxykvq6gbylsXQskBBBnGy3tW/AMOM # CZIVNSaz7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+rx3rKWDEJlIqLXvJWnY0v5ydP # pOjL6s36czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvUBDx6z1ev+7psNOdgJMoiwOrU # G2ZdSoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl9VnePs6BaaeEWvjJSjNm2qA+ # sdFUeEY0qVjPKOWug/G6X5uAiynM7Bu2ayBjUwIDAQABo4IBXTCCAVkwEgYDVR0T # AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU729TSunkBnx6yuKQVvYv1Ensy04wHwYD # VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG # A1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV # HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU # cnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1s # BwEwDQYJKoZIhvcNAQELBQADggIBABfO+xaAHP4HPRF2cTC9vgvItTSmf83Qh8WI # GjB/T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQM2qEJPe36zwbSI/mS83afsl3YTj+ # IQhQE7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy9lMDPjTLxLgXf9r5nWMQwr8M # yb9rEVKChHyfpzee5kH0F8HABBgr0UdqirZ7bowe9Vj2AIMD8liyrukZ2iA/wdG2 # th9y1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1UH410ANVko43+Cdmu4y81hjaj # V/gxdEkMx1NKU4uHQcKfZxAvBAKqMVuqte69M9J6A47OvgRaPs+2ykgcGV00TYr2 # Lr3ty9qIijanrUR3anzEwlvzZiiyfTPjLbnFRsjsYg39OlV8cipDoq7+qNNjqFze # GxcytL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0vw9vODRzW6AxnJll38F0cuJG # 7uEBYTptMSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/DJbg3s6KCLPAlZ66RzIg9sC+N # Jpud/v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHbxtl5TPau1j/1MIDpMPx0LckT # etiSuEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAPvIXKUjPSxyZsq8WhbaM2tszW # kPZPubdcMIIG7TCCBNWgAwIBAgIQCoDvGEuN8QWC0cR2p5V0aDANBgkqhkiG9w0B # AQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/ # BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYg # U0hBMjU2IDIwMjUgQ0ExMB4XDTI1MDYwNDAwMDAwMFoXDTM2MDkwMzIzNTk1OVow # YzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQD # EzJEaWdpQ2VydCBTSEEyNTYgUlNBNDA5NiBUaW1lc3RhbXAgUmVzcG9uZGVyIDIw # MjUgMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANBGrC0Sxp7Q6q5g # VrMrV7pvUf+GcAoB38o3zBlCMGMyqJnfFNZx+wvA69HFTBdwbHwBSOeLpvPnZ8ZN # +vo8dE2/pPvOx/Vj8TchTySA2R4QKpVD7dvNZh6wW2R6kSu9RJt/4QhguSssp3qo # me7MrxVyfQO9sMx6ZAWjFDYOzDi8SOhPUWlLnh00Cll8pjrUcCV3K3E0zz09ldQ/ # /nBZZREr4h/GI6Dxb2UoyrN0ijtUDVHRXdmncOOMA3CoB/iUSROUINDT98oksouT # MYFOnHoRh6+86Ltc5zjPKHW5KqCvpSduSwhwUmotuQhcg9tw2YD3w6ySSSu+3qU8 # DD+nigNJFmt6LAHvH3KSuNLoZLc1Hf2JNMVL4Q1OpbybpMe46YceNA0LfNsnqcnp # JeItK/DhKbPxTTuGoX7wJNdoRORVbPR1VVnDuSeHVZlc4seAO+6d2sC26/PQPdP5 # 1ho1zBp+xUIZkpSFA8vWdoUoHLWnqWU3dCCyFG1roSrgHjSHlq8xymLnjCbSLZ49 # kPmk8iyyizNDIXj//cOgrY7rlRyTlaCCfw7aSUROwnu7zER6EaJ+AliL7ojTdS5P # WPsWeupWs7NpChUk555K096V1hE0yZIXe+giAwW00aHzrDchIc2bQhpp0IoKRR7Y # ufAkprxMiXAJQ1XCmnCfgPf8+3mnAgMBAAGjggGVMIIBkTAMBgNVHRMBAf8EAjAA # MB0GA1UdDgQWBBTkO/zyMe39/dfzkXFjGVBDz2GM6DAfBgNVHSMEGDAWgBTvb1NK # 6eQGfHrK4pBW9i/USezLTjAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYI # KwYBBQUHAwgwgZUGCCsGAQUFBwEBBIGIMIGFMCQGCCsGAQUFBzABhhhodHRwOi8v # b2NzcC5kaWdpY2VydC5jb20wXQYIKwYBBQUHMAKGUWh0dHA6Ly9jYWNlcnRzLmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRpbWVTdGFtcGluZ1JTQTQwOTZT # SEEyNTYyMDI1Q0ExLmNydDBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vY3JsMy5k # aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2 # U0hBMjU2MjAyNUNBMS5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9 # bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQBlKq3xHCcEua5gQezRCESeY0ByIfjk9iJP # 2zWLpQq1b4URGnwWBdEZD9gBq9fNaNmFj6Eh8/YmRDfxT7C0k8FUFqNh+tshgb4O # 6Lgjg8K8elC4+oWCqnU/ML9lFfim8/9yJmZSe2F8AQ/UdKFOtj7YMTmqPO9mzskg # iC3QYIUP2S3HQvHG1FDu+WUqW4daIqToXFE/JQ/EABgfZXLWU0ziTN6R3ygQBHMU # BaB5bdrPbF6MRYs03h4obEMnxYOX8VBRKe1uNnzQVTeLni2nHkX/QqvXnNb+YkDF # kxUGtMTaiLR9wjxUxu2hECZpqyU1d0IbX6Wq8/gVutDojBIFeRlqAcuEVT0cKsb+ # zJNEsuEB7O7/cuvTQasnM9AWcIQfVjnzrvwiCZ85EE8LUkqRhoS3Y50OHgaY7T/l # wd6UArb+BOVAkg2oOvol/DJgddJ35XTxfUlQ+8Hggt8l2Yv7roancJIFcbojBcxl # RcGG0LIhp6GvReQGgMgYxQbV1S3CrWqZzBt1R9xJgKf47CdxVRd/ndUlQ05oxYy2 # zRWVFjF7mcr4C34Mj3ocCVccAvlKV9jEnstrniLvUxxVZE/rptb7IRE2lskKPIJg # baP5t2nGj/ULLi49xTcBZU8atufk+EMF/cWuiC7POGT75qaL6vdCvHlshtjdNXOC # IUjsarfNZzGCBkQwggZAAgEBMGgwVDELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1Nl # Y3RpZ28gTGltaXRlZDErMCkGA1UEAxMiU2VjdGlnbyBQdWJsaWMgQ29kZSBTaWdu # aW5nIENBIFIzNgIQB5zg5NEUf4XNOXPPdi036zANBglghkgBZQMEAgEFAKCBhDAY # BgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3 # AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEi # BCCT1HlWC3Qu4ARYc0HVUBdmwj+YAQWpUh1cDmqr+LJaPjANBgkqhkiG9w0BAQEF # AASCAgAVzJewL9E4E9kWCwJwctTM1PzqV+YZWPeG3MH9gR7roTkIQpJWnN6CFxao # CQGIl3F5DYa66qWBKsP9/3rgZuq3HE1SvXCoaPuwnQFW6YveZOoFHMrG89MdckKB # TKDPqZ6nFLivMw2CoeII7EYzy1/fje0NWgM4t07TX2cehwc25NwPz9XmSntDCCSY # f7BnXxi0Py1PbTSVlgBjJYPQopiAt+Hxyi/7sZZV9iG8mM2udqOV/gjZnW87bwQq # 6IsiDQzJD7y7i0wN9xnYa7RE+Tb/xfjVkwVaYgfJI1256f5ZC5koVxMAZik0OBMC # rWpoZJPW87Cq14R7Cj5TZkz0IZy9VFsqT8J9CmZYCw26c/N7yqKB7qBV+0/+aSfj # +kcg1yptNoYOJWDfa+rutigQAEA/MeRl5R4/swx9Ybej+oTJF587kXcRRGOoXNzt # qAt0omcN9cMYaghch+gcvNxizDbi69yDoiF+jZGhUtM0AezW4KuOwADtAELJknSM # QpJLHO4AXu262oLvdgZrb1Z7MF7q5+VZ1u66wlhdzSw3u3KEjuezh0DtiMI//vLj # waDc1yUcjYHJ7Eolg7h77RxgY6ofpC7/n3pg5LxKfvk67LkauooQiT075NRJ00Sz # RA5iVn+TbLCKLOH0QrbuYYzwydhPCHRXabHDCRnjIIEj9dtYyKGCAyYwggMiBgkq # hkiG9w0BCQYxggMTMIIDDwIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5E # aWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1l # U3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTECEAqA7xhLjfEFgtHEdqeV # dGgwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwG # CSqGSIb3DQEJBTEPFw0yNjA0MTkxNzIwMjhaMC8GCSqGSIb3DQEJBDEiBCBY65jS # 5aE7W3r1yhzH2nNW44h/xqAVf0fGWGUutOH7ajANBgkqhkiG9w0BAQEFAASCAgCO # 6n/XamjAvo4KEr+6kaJG6IGEcSLktdImtJlNrck/Z40v2c6feUAAYbmNp4vvOAR7 # zU4mJpsuLDoubPbeBwFGzD0KAOPqUjp4FgI8ZWBbG94aLVyP37/Ga5xwLw6PYf5Q # 0FoFyaGkV1guaukyK/EbwBMfGOolbxrp3EoU5qSitBXmaSLNrJoK06SZ/9kKARwo # i+sFBqxXm+SG5MYPGIBtT/mwJjy2VZG4PgEuDI5nfZVh6U0ITFhVWnV3UmovV8kf # tc5+V5gBRqVPsd/7/NkqwQoK891F0Vd2Ibu+gP5hz5oxS5jgaRghzLzWIHVkLAkT # /9tM7CrY5Vzr41K9PILqnSBajuBu4lB/dTA5H+6iPrbF0dyo3fBe89HLhMKNDOEv # 3LhSgB4FnOrRe1IFpPHvNLQ/u1eHG74d7utEdqT6tvcjitGrejPXeeuGx8YbWBap # zzuaby0IiO1UiERgCefhClYYimzAIJse4vS05DtFbL1zWvOCCmhUV01A4XyutPCy # xtZxZJVM18NJimEKmWpiFDhoY5dAPj4/amPwVNzk0sh2202YFS4CwMhi4kfXSCDa # 58hNaBNyOLyGN9lp3z79UJJqcQVypj59Um4Qk5RVqgdw+mNPVmDTw+xWDzDkazyN # hKFlm1ZjEYVPEWKJeG0dBBSQVSdDMcTUQAopLSXHog== # SIG # End signature block |