scenarios/LLDP/LLDP.ps1
param ( [object]$EventInfo ) Write-Host $EventInfo.EventArgs Write-Host $EventInfo.EventArgs.Data Add-Type -Path "$PSScriptRoot\..\..\Microsoft.NetworkHud.Module.dll" -ErrorAction SilentlyContinue $dictionary = [Microsoft.NetworkHud.Module.SharedConcurrentDictionary]::GetInstance("LLDP") $config = (Import-PowerShellDataFile "$PSScriptRoot\..\Config.psd1").PublishLLDP Import-LocalizedData -BindingVariable "LocMessage" -FileName "LocalizationMessages" -BaseDirectory $PSScriptRoot\..\..\ $logName = 'NetworkHud' $script:AdapterName = "" $helpersPath = Join-Path -Path $PSScriptRoot -ChildPath '..\helpers' Import-Module "$helpersPath\helper.HealthFaults.psm1" Import-Module "$helpersPath\helper.ClusterRegistry.psm1" Add-FaultApi Add-HciClusterRegistryUtils #Used to trigger downstream scenarios function Write-CustomTriggerEvent { param ( [int] $EventID, [string] $PropertyName, [string] $Adapters ) $logName = 'NetworkHud' Write-EventLog -LogName $logName ` -Source $($config.PropertyChange.Source) ` -EventID $EventID ` -EntryType $($config.PropertyChange.EntryType) ` -Message $($LocMessage.$($config.PropertyChange.MessageKey) -f $PropertyName, $Adapters) } function Write-CustomFault{ param( [string] $MissingProperty ) $hostname = hostname $faultDescription = $LocMessage.$($config.FaultDescriptionKey) -f $script:AdapterName, $hostname, $MissingProperty $faultAction = $LocMessage.$($config.FaultActionKey) $ID = "$($env:ComputerName): $($script:AdapterName)" [Microsoft.NetworkHud.Module.HciHealthUtils]::HciModifyFault($config.EntityType, $ID, "", "", "", $FRApiActionModify, $config.FaultType, $HealthUrgencyUnHealthy, "", $faultDescription, $faultAction, 0) | Out-Null [Microsoft.NetworkHud.Module.HciHealthUtils]::HciModifyRelationship($config.EntityType, $ID, "", "", "", $FRApiActionModify, "Microsoft.Health.EntityType.Server", $env:COMPUTERNAME, "", "", "", $HealthRelationshipGroupKey, $HealthUrgencyUnHealthy, $HealthRelationshipCollection, 0) | Out-Null } function Get-TlvChassisIdData { param ( [byte[]] $chasBytes ) if(-not $chasBytes){ return "Unknown" } # get the Chassis ID Subtype [int]$chasIdType = "0x$($chasBytes[0])" switch -Regex ($chasIdType) { "[1-3]"{return ( [System.Text.Encoding]::ASCII.GetString($chasBytes[1..($chasBytes.Length - 1)]) )} "4"{return ("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}" -f $chasBytes[1..($chasBytes.Length - 1)])} Default { Write-Warning "Unknown Chassis ID type: $chasIdType" return "Unknown" } } } function Get-TlvPortIdData { param ( [byte[]] $portBytes ) if(-not $portBytes){ return "Unknown" } # get the Chassis ID Subtype [int]$portIdType = "0x$($portBytes[0])" Write-Verbose "Get-TlvPortId - Port Type: $portIdType" switch -Regex ($portIdType) { "[1-2]|[5]"{return ( [System.Text.Encoding]::ASCII.GetString($portBytes[1..($portBytes.Length - 1)]) )} "3"{return ("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}" -f $portBytes[1..($portBytes.Length - 1)])} Default { Write-Warning "Unknown Port ID type: $portIdType" return "Unknown" } } } function Get-TlvVLANIdData{ param ( [object[]] $Data ) if(-not $Data){ Write-CustomFault -MissingProperty "VLANID" return "Unknown" } $list = @() foreach($i in $Data){ #Bitshift the first byte by 8, add the second byte $list+= [convert]::ToSingle($i.data[0]) * [math]::Pow(2,8) + [convert]::ToSingle($i.data[1]) } return $list } function Get-MaxFrameSize{ param ( [object[]] $Data ) if(-not $Data){ Write-CustomFault -MissingProperty "MaxFrameSize" return "Unknown" } return $Data } function Get-NativeVLAN{ param ( [object[]] $Data ) if(-not $Data){ Write-CustomFault -MissingProperty "NativeVLAN" return "Unknown" } return $Data } function Get-LinkAggregationData{ param ( [object[]] $Data ) if(-not $Data){ Write-CustomFault -MissingProperty "LinkAggregation" return "Unknown" } return $Data } function Get-ETSConfigurationData{ param ( [object[]] $Data ) if(-not $Data){ Write-CustomFault -MissingProperty "ETSConfiguration" return "Unknown" } return $Data } function Get-PFCConfigurationData{ param ( [object[]] $Data ) if(-not $Data){ Write-CustomFault -MissingProperty "PFCConfiguration" return "Unknown" } return $Data[1] } #Takes in adapter obj, retunes hashtable, may require helpers function Parse-Adapter { param ( [object] $Adapter ) $adapterInfo = Get-NetAdapter -Name $Adapter.Name $script:AdapterName = $Adapter.Name $LLDPInfo = (Get-NetLldpAgent -NetAdapterName $Adapter.Name).Neighbor $TLVinfo = $LLDPInfo.Tlvs $output = New-Object "System.Collections.Generic.Dictionary[System.String,System.String]" $output["InterfaceName"] = $Adapter.Name $output["InterfaceIndex"] = $adapterInfo.InterfaceIndex $output["Destination"] = "01:80:c2:00:00:0e" $output["SourceMac"] = $LLDPInfo.PhysicalAddress $output["EtherType"] = "0x88CC" $output["ChassisID"] = Get-TlvChassisIdData ($TLVinfo | Where-Object TLVType -eq 1).data $output["PortID"] = Get-TlvPortIdData ($TLVinfo | Where-Object TLVType -eq 2).data $output["TimeToLive"] = ($TLVinfo | Where-Object TLVType -eq 3).data $output["VLANID"] = Get-TlvVLANIdData -data ($TLVinfo | Where-Object { $_.TLVType -eq 127 -and $_.OuiSubtype -eq 3 -and $_.TlvName -notlike "Link Aggregation"}) $output["MaxFrameSize"] = Get-MaxFrameSize -data ($TLVinfo | Where-Object { $_.TLVType -eq 127 -and $_.OuiSubtype -eq 4 }) $output["NativeVLAN"] = Get-NativeVLAN -data ($TLVinfo | Where-Object { $_.TLVType -eq 127 -and $_.OuiSubtype -eq 1 }) $output["LinkAggregation"] = Get-LinkAggregationData -data ($TLVinfo | Where-Object { $_.TLVType -eq 127 -and $_.OuiSubtype -eq 7 }) $output["ETS"] = Get-ETSConfigurationData -data ($TLVinfo | Where-Object { $_.TLVType -eq 127 -and $_.OuiSubtype -eq 9 }) $output["PFC"] = Get-PFCConfigurationData -data ($TLVinfo | Where-Object { $_.TLVType -eq 127 -and $_.OuiSubtype -eq 11 }).Data return $output } #CluderDB open $clusterKey = OpenCluster $keyHandle = CreateAndOpenKey -keyHandle $clusterKey -KeyName "NetworkHUD\\LLDP" #Parse and concurrent dictionsary $nodeID = Hostname $propertiesChanged = @{} $adapterList = Get-NetAdapter | Where-Object {($_.MediaType -eq '802.3') -and ($_.Status -eq 'Up')} $adapterTable = New-Object "System.Collections.Generic.Dictionary[System.String,System.Collections.Generic.Dictionary[System.String,System.String]]" foreach($Adapter in $adapterList){ #Skip over the virtual adapters if($Adapter.InterfaceDescription -match "Hyper-V"){ continue } #Enable LLDP Enable-NetLLDPAgent -NetAdapterName $Adapter.name #Check if it exists in the dictionsary $existingtable = $dictionary[$Adapter.name] if(-not $existingtable){ Write-Debug "No existing data found in memory for adapter {$($Adapter.name)}" $clusterTable = (Get-ItemProperty -Path "HKLM:\Cluster\NetworkHud\LLDP").$nodeID if($clusterTable){ $existingtable = $clusterTable } else{ Write-Debug "No existing data found in the clusterDB for adapter {$($Adapter.name)}" $dictionary[$Adapter.Name] = New-Object "System.Collections.Generic.Dictionary[System.String,System.String]" $existingtable = $dictionary[$Adapter.Name] } } $parsedTable = Parse-Adapter -Adapter $Adapter $adapterTable[$Adapter.name] = $parsedTable $dictionary[$Adapter.Name] = $parsedTable foreach($property in $parsedTable.keys){ $parsedvalue = $parsedTable[$property] $existingvalue = $existingtable[$property] if($parsedvalue -ne $existingvalue){ Write-Debug "different value found for the property {$property}, Parsed value: {$parsedvalue} is different from the existing value {$existingvalue} for adapter {$($Adapter.Name)}. Triggering a downstream scenario" if(-not $propertiesChanged[$property]) {$propertiesChanged[$property] = New-Object -TypeName "System.Collections.ArrayList" } $propertiesChanged[$property] += $Adapter.name } } } #Write into clusterDB and close handle SetValue -KeyHandle $keyHandle -KeyName $nodeID -Data ($dictionary | ConvertTo-Json).toString() Write-Debug "Dictionary $(($dictionary | ConvertTo-Json).toString())" CloseKey -KeyHandle $keyHandle CloseCluster -ClusterHandle $clusterKey #Trigger consumer scenarios foreach ($property in $propertiesChanged.keys){ switch ($property) { ChassisID { Write-CustomTriggerEvent -EventID 10001 -PropertyName "ChassisID" -Adapters ($propertiesChanged[$property] -join ", ")} EtherHead{ Write-CustomTriggerEvent -EventID 10002 -PropertyName "EtherHead" -Adapters ($propertiesChanged[$property] -join ", ")} VLANID { Write-CustomTriggerEvent -EventID 10003 -PropertyName "VLANID" -Adapters ($propertiesChanged[$property] -join ", ")} NativeVLAN { Write-CustomTriggerEvent -EventID 10004 -PropertyName "NativeVLAN" -Adapters ($propertiesChanged[$property] -join ", ")} LinkAggregation { Write-CustomTriggerEvent -EventID 10005 -PropertyName "LinkAggregation" -Adapters ($propertiesChanged[$property] -join ", ")} ETS { Write-CustomTriggerEvent -EventID 10006 -PropertyName "ETSConfiguration" -Adapters ($propertiesChanged[$property] -join ", ")} PFC { Write-CustomTriggerEvent -EventID 10007 -PropertyName "PFCConfiguration" -Adapters ($propertiesChanged[$property] -join ", ")} Default { } } } # SIG # Begin signature block # MIIoLQYJKoZIhvcNAQcCoIIoHjCCKBoCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCd3eifcgSV+u+1 # 0ooD6Iud1C3lDECFcPzeuKgx/z/YNaCCDXYwggX0MIID3KADAgECAhMzAAADTrU8 # esGEb+srAAAAAANOMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjMwMzE2MTg0MzI5WhcNMjQwMzE0MTg0MzI5WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDdCKiNI6IBFWuvJUmf6WdOJqZmIwYs5G7AJD5UbcL6tsC+EBPDbr36pFGo1bsU # p53nRyFYnncoMg8FK0d8jLlw0lgexDDr7gicf2zOBFWqfv/nSLwzJFNP5W03DF/1 # 1oZ12rSFqGlm+O46cRjTDFBpMRCZZGddZlRBjivby0eI1VgTD1TvAdfBYQe82fhm # WQkYR/lWmAK+vW/1+bO7jHaxXTNCxLIBW07F8PBjUcwFxxyfbe2mHB4h1L4U0Ofa # +HX/aREQ7SqYZz59sXM2ySOfvYyIjnqSO80NGBaz5DvzIG88J0+BNhOu2jl6Dfcq # jYQs1H/PMSQIK6E7lXDXSpXzAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUnMc7Zn/ukKBsBiWkwdNfsN5pdwAw # RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW # MBQGA1UEBRMNMjMwMDEyKzUwMDUxNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci # tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG # CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0 # MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAD21v9pHoLdBSNlFAjmk # mx4XxOZAPsVxxXbDyQv1+kGDe9XpgBnT1lXnx7JDpFMKBwAyIwdInmvhK9pGBa31 # TyeL3p7R2s0L8SABPPRJHAEk4NHpBXxHjm4TKjezAbSqqbgsy10Y7KApy+9UrKa2 # kGmsuASsk95PVm5vem7OmTs42vm0BJUU+JPQLg8Y/sdj3TtSfLYYZAaJwTAIgi7d # hzn5hatLo7Dhz+4T+MrFd+6LUa2U3zr97QwzDthx+RP9/RZnur4inzSQsG5DCVIM # pA1l2NWEA3KAca0tI2l6hQNYsaKL1kefdfHCrPxEry8onJjyGGv9YKoLv6AOO7Oh # JEmbQlz/xksYG2N/JSOJ+QqYpGTEuYFYVWain7He6jgb41JbpOGKDdE/b+V2q/gX # UgFe2gdwTpCDsvh8SMRoq1/BNXcr7iTAU38Vgr83iVtPYmFhZOVM0ULp/kKTVoir # IpP2KCxT4OekOctt8grYnhJ16QMjmMv5o53hjNFXOxigkQWYzUO+6w50g0FAeFa8 # 5ugCCB6lXEk21FFB1FdIHpjSQf+LP/W2OV/HfhC3uTPgKbRtXo83TZYEudooyZ/A # Vu08sibZ3MkGOJORLERNwKm2G7oqdOv4Qj8Z0JrGgMzj46NFKAxkLSpE5oHQYP1H # tPx1lPfD7iNSbJsP6LiUHXH1MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # 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 # /Xmfwb1tbWrJUnMTDXpQzTGCGg0wghoJAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAANOtTx6wYRv6ysAAAAAA04wDQYJYIZIAWUDBAIB # BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIMD+/DgyRMYnKUqvVZmtQb6d # rdDso2i5eylyDod007GlMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A # cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB # BQAEggEAaViqw/9L9eSBYWRfCSaxsvBP8asEmKo2wby3+OqenEQbKxqu5TOFJcAq # LGOmL2A+hneHBAtEwRy/gagkk2kZuDbaBOiw8fo8EKMaZ08AD1HQvNa4WYxSmflf # SxgOs8w3I0AgUtnAYvu2DyF4RyBdzk3NKHHymTtvmM9EFiOc8RwPl0ctxtjGxQIL # qOooWircBv/QBkplDztjSrWG4zoDMI2hTeu770fQoJDe0NsGSQu0Ty2xnsjBfDDx # ZANcZ2Cmsvv6zLAqoh3slY/5s7eLi2eAGKGKRiQP1WXY8Rd+XCQbAt3Wk88rZcf6 # BnGXBzghEGNtgaaok1UIN6VwfHLBc6GCF5cwgheTBgorBgEEAYI3AwMBMYIXgzCC # F38GCSqGSIb3DQEHAqCCF3AwghdsAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq # hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl # AwQCAQUABCClcdScinvban5k18mFNN2HApaLgkj4Yn30/Iuwd0IqJQIGZSivjmxu # GBMyMDIzMTEwOTIxMzAzOS4wMDdaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l # cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046RTAwMi0w # NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg # ghHtMIIHIDCCBQigAwIBAgITMwAAAdmcXAWSsINrPgABAAAB2TANBgkqhkiG9w0B # AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD # VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMzA2MDExODMy # NThaFw0yNDAyMDExODMyNThaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz # aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv # cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z # MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046RTAwMi0wNUUwLUQ5NDcxJTAjBgNV # BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQDV6SDN1rgY2305yLdCdUNvHCEE4Z0ucD6CKvL5lA7H # M81SMkW36RU77UaBL9PScviqfVzE2r2pRbRMtDBMwEx1iaizV2EZsNGGuzeR3XNY # ObQvJVLaCiBktAZdq75BNFIil+SfdpXgKzVQZiDBJDN50WCADNrrb48Z4Z7/Kvyz # aD4Gb+aZeCioB2Gg1m53d+6pUTBc3WO5xHZi/rrI/XdnhiE6/bspjpU5aufClIDx # 0QDq1QRw04adrKhcDWyGL3SaBp/hjN+4JJU7KzvsKWZVdTuXPojnaTwWcHdEGfzx # iaF30zd8SY4YRUcMGPOQORH1IPwkwwlqQkc0HBkJCQziaXY/IpgMRw/XP4Uv+JBJ # 8RZGKZN1zRPWT9d5vHGUSmX3m77RKoCfkgSJifIiQi6Fc0OYKS6gZOA7nd4t+liA # rr9niqeC/UcNOuVrcVC4CbkwfJ2eHkaWh18sUt3UD8QHYLQwn95P+Hm8PZJigr1S # RLcsm8pOPee7PBbndI/VeKJsmQdjek2aFO9VGnUtzDDBowlhXshswZMMkLJ/4jUz # QmUBfm+JAH1516E+G02wS7NgzMwmpHWCmAaFdd7DyJIqGa6bcZrR7QALdkwIhVQD # gzZAuNxqwvh4Ia4ZI5Voyj4b7zWAhmurpwpMpijz+ieeWwf6ZdmysRjR/yZ6UXmG # awIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFBw6wSlTZ6gFXl05w/s3Ga1f51wnMB8G # A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG # Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy # MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w # XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy # dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG # A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD # AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQAqNtVYLO61TMuIanC7clt0i+XRRbHwnwNo # 05Q3s4ppFtd4nCmB/TJPDJ6uvEryxs0vw5Y+jQwUiKnhl2VGGwIq0pWDIuaW4ppM # V1pYQfJ6dtBGkRiTP1eKVvARYZMRaITe9ZhwJJnYP83pMxHCxaEsZC4ilY3/55dq # d4ZXTCz/cpG5anmDartnWmgysygNstTwbWJJRj85gYRkjxi/nxKAiEFxl6GfkcnX # Vy8DRFQj1d3AiqsePoeIzxu1iuAJRwDrfe4NnKHqoTgWsv7eCWJnWjWWRt7RRGrp # vzLQo/BxUb8i49UwRg9G5bxpd5Su1b224Gv6G1HRU+qJHB1zoe41D2r/ic2BPous # V9neYK5qI5PHLshAn6YTQllbV9pCbOUvZO0dtdwp5HH2fw6ofJNwKcPElaqkEcxv # rhhRWqwNgaEVTyIV4jMc8jPbx2Nh9zAztnb9NfnDFOE+/gF8cZqTa/T65TGNP3uM # iP3gr8nIXQ2IRwMVUoLmGu2qfmhDoews3dcvk6s1aA6mXHw+MANEIDKKjw3i2G6J # tZkEemu1OXtskg/tGnfywaMgq5CauU9b6enTtA+UE+GKnmiQW6YUHPhBI0L2QG76 # TRBre5PpNVHiyc/01bjUEMpeaB+InAH4nDxYXx18wbJE+e/IbMv0147EFL792dEL # F0XwqqcU0TCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI # hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw # DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x # MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy # MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp # bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC # AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg # M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF # dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6 # GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp # Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu # yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E # XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0 # lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q # GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ # +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA # PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw # EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG # NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV # MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj # cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK # BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC # AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX # zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v # cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI # KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG # 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x # M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC # VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449 # xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM # nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS # PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d # Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn # GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs # QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL # jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL # 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNQ # MIICOAIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw # b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn # MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOkUwMDItMDVFMC1EOTQ3MSUwIwYDVQQD # ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQDi # HEW6Ca3n5BgZV/tQ/fCR09Tf96CBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w # IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA6PdsRzAiGA8yMDIzMTEwOTE0MzM0 # M1oYDzIwMjMxMTEwMTQzMzQzWjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDo92xH # AgEAMAoCAQACAiEGAgH/MAcCAQACAhNOMAoCBQDo+L3HAgEAMDYGCisGAQQBhFkK # BAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJ # KoZIhvcNAQELBQADggEBAC4jaLMUyjCjulG4c32j2Y1qJUInZWc/R5PmjTlRiljD # lG2+bFzx1RyXeqPJgtHxxRJlxO3++/vdX4exzeuoHes/NH42rPnECLfSiEZCmXaY # aLjrAl9C2Oxxht03P6z2Ul8EgezBz5ta7jep+Czgf2GjeGEhSbRibznMPogwXGCp # UvH4tK+RGf1oovctg/ShNut1MGFoP+TaoQq5rDx9CCCjd3+LT3PzJDac81eNCshC # 9BdKKvzRgux3yABW63NWwe6s3cPRId8BBjHPTzDAZisckeyYBLALBxBO3nzbzCMc # WzbevPhId6zRJ4OVY83TrAQrHVm6muuBqmGZyWfvHlsxggQNMIIECQIBATCBkzB8 # MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk # bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N # aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAdmcXAWSsINrPgABAAAB # 2TANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEE # MC8GCSqGSIb3DQEJBDEiBCB4dgEax7OPQ91VfXCYKCWh7VsU2t6l/gmgnOd6/ZdE # YTCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIJ+gFbItOm/UMDAnETzbJe0u # 0DWd2Mgpgb0ScbQgB3nzMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT # Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB # IDIwMTACEzMAAAHZnFwFkrCDaz4AAQAAAdkwIgQg6i3rxm4DU9/cGMTIbdWWHDhj # ByJcY5V+qBXaG8X8yFgwDQYJKoZIhvcNAQELBQAEggIAWfa0o5UZYtPvg03amClW # z35OuBRCtsy89xHgJkgxtByN8w3RVi9f/6DzFSHOpb2COwQQ355VtYkktKugf16n # VAPsNgkVXkmoA3T1n9kmo/b2NfnVw0B6EJcQKTj0QEqPv2x8oS884rrhTMcI4NDV # 9t6Dw24TZfZGZ7kg62Mqe6bPbkEe+gySyyM4cYXrXe0XzqVkD3YUHJrmmxhO8RNA # IkYGioar1vCoJxWXa9lzckn+vlnNTOWwKDs812cYsYS7sVnhTLr5DQqhZr3gD2yj # MvYHPM9j+4ZYmtE6+IHBPThOI0dfyJzMrvB8IHhVh5tOVwJL6KM6gADdGbQberN+ # hKMZkWmxEkkG72dEEId5Uy88aO2Tc/YDQZURjlsYRX/chI8Tu6c6LkDJubz1RU/3 # Tn93N6U57PNbnbSd99R0h72kwCfeSTPp5Qpd8PEYH/N1Sbdm/JDt6zzXvlaSZWjh # kgI/LJRzgyCQdZbcIv+SrWupGP4baBdVhQ+YrfLKZirB3MRi+NNEbXQiq/UFuWei # 8SoYH/7YN9bzjLFxK0/2R6aUpKhuHeJ7wIvUtUP27xhPrZLMtBhqkDmIet/6cJOf # fdYh4ckcQdCpH/sLtt37OW8kgDDp4iQ07eytIqtGIWFQpGiEmksFwIeTVpwkxlc4 # BqEdTUZCH6B+ECcbQILjLlM= # SIG # End signature block |