Bin/ADSyncDiagnostics/PSScripts/ADSyncDiagnosticsUtils.ps1
#------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. #------------------------------------------------------------------------- # # Returns given date-time by locale 'en-us' # Function Global:GetDateTimeLocaleEnUs { param ( [DateTime] [parameter(mandatory=$true)] $DateTime ) $culture = New-Object System.Globalization.CultureInfo 'en-us' $dateTime = $($DateTime.ToUniversalTime()).ToString($culture) Write-Output $dateTime } # # Emit events in order to track usage and problems through ADHealth # Function Global:WriteEventLog { param ( [int] [parameter(mandatory=$true)] $EventId, [string] [parameter(mandatory=$true)] $Message ) Write-EventLog -LogName "Application" -Source "Directory Synchronization" -EventID $EventId -EntryType Information -Message $Message -Category 0 } Function Global:GetValidADForestCredentials { param ( [string] [parameter(mandatory=$true)] $ADForestName ) while ($true) { $ADForestCredential = Get-Credential -Message "Please enter credentials for an AD account that has permissions to read all attributes on the target object. Use the fully qualified domain name of the account (Example: CONTOSO\admin):" $networkCredential = $ADForestCredential.GetNetworkCredential() if ($networkCredential.UserName.Contains("@") -or $networkCredential.Domain.ToString() -eq "") { "Credential should use the fully qualified domain name of the account. Example: CONTOSO\admin" | Write-Host -fore Red Write-Host "`r`n" } else { try { $credentialTestContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext([System.DirectoryServices.ActiveDirectory.DirectoryContextType]::Forest, $ADForestName, $ADForestCredential.UserName, $networkCredential.Password) $credentialTestForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($credentialTestContext) return $ADForestCredential } catch { "Invalid Credentials. Details: $($_.Exception.Message)" | Write-Host -fore Red Write-Host "`r`n" } } $retryCredentialOptions = [System.Management.Automation.Host.ChoiceDescription[]] @("&Provide credentials", "&Back to previous") $retryCredential = !($host.UI.PromptForChoice("Credentials Invalid", "Provide credentials again or return to previous menu?", $retryCredentialOptions, 0)) if (!$retryCredential) { return $null } } } Function Global:GetADConnectors { $adConnectors = Get-ADSyncConnector | Where-Object {$_.ConnectorTypeName -eq "AD"} Write-Output $adConnectors } Function Global:GetADConnectorByName { param ( [string] [parameter(mandatory=$false)] [AllowNull()] $ADConnectorName, [string] [parameter(mandatory=$false)] $PromptMessage ) while ([string]::IsNullOrEmpty($ADConnectorName)) { $adConnectors = GetADConnectors if ($adConnectors -eq $null) { "No AD Connector is found." | ReportError Write-Host "`r`n" $ADConnectorName = $null return } Write-Host "`r`n" Write-Host "List of AD Connectors:" Write-Host "----------------------" foreach ($adConnector in $adConnectors) { Write-Host $adConnector.Name } if ($adConnectors.length -eq 1) { $ADConnectorName = $adConnectors[0].Name } else { Write-Host "`r`n" $ADConnectorName = Read-Host $PromptMessage } } $adConnector = Get-ADSyncConnector | Where-Object {($_.ConnectorTypeName -eq "AD") -and ($_.Name -eq $ADConnectorName)} Write-Output $adConnector } Function Global:GetAADConnector { $aadConnectors = Get-ADSyncConnector | Where-Object {$_.Identifier -eq "b891884f-051e-4a83-95af-2544101c9083"} if ($aadConnectors -eq $null) { Write-Output $null } else { Write-Output $aadConnectors[0] } } Function Global:GetAADTenantName { param ( [Microsoft.IdentityManagement.PowerShell.ObjectModel.Connector] [parameter(mandatory=$true)] $AADConnector ) $aadConnectorUserName = $AADConnector.ConnectivityParameters["UserName"].Value $aadTenantName = $($aadConnectorUserName.Split('@'))[1] Write-Output $aadTenantName } Function Global:GetCSObject { param ( [string] [parameter(mandatory=$true)] $ConnectorName, [string] [parameter(mandatory=$true)] $DistinguishedName ) Try { $csObject = Get-ADSyncCSObject -ConnectorName $ConnectorName -DistinguishedName $DistinguishedName Write-Output $csObject } Catch { Write-Output $null } } Function Global:GetCSObjectByIdentifier { param ( [Guid] [parameter(mandatory=$true)] $CsObjectId ) Try { $csObject = Get-ADSyncCSObject -Identifier $CsObjectId Write-Output $csObject } Catch { Write-Output $null } } Function Global:GetMVObjectByIdentifier { param ( [Guid] [parameter(mandatory=$true)] $MvObjectId ) Try { $mvObject = Get-ADSyncMVObject -Identifier $MvObjectId Write-Output $mvObject } Catch { Write-Output $null } } Function Global:GetTargetCSObjectId { param ( [Microsoft.IdentityManagement.PowerShell.ObjectModel.MvObject] [parameter(mandatory=$true)] $MvObject, [Guid] [parameter(mandatory=$true)] $TargetConnectorId ) foreach ($mvObjectLink in $MvObject.Lineage) { if ($mvObjectLink.ConnectorId -eq $TargetConnectorId) { Write-Output $mvObjectLink.ConnectedCsObjectId return } } Write-Output $null } Function Global:IsStagingModeEnabled { $isStagingModeEnabled = $false $globalParameters = Get-ADSyncGlobalSettingsParameter $stagingModeGlobalParameter = $globalParameters | Where-Object {$_.Name -eq "Microsoft.Synchronize.StagingMode"} if ($stagingModeGlobalParameter -ne $null) { $isStagingModeEnabled = $stagingModeGlobalParameter.Value } Write-Output $isStagingModeEnabled } Function Global:ConvertADObjectToHashTable { param ( [System.Collections.Generic.Dictionary[[String], [Object]]] [parameter(mandatory=$true)] $AdObject, [bool] [parameter(mandatory=$false)] $AllAttributes ) $ADObjectHashTable = @{} if ($AllAttributes) { foreach ($attributeName in $AdObject.Keys) { $attributeValues = [System.Collections.ArrayList] $AdObject[$attributeName] $ADObjectHashTable[$attributeName] = New-Object System.Collections.Generic.List[String] foreach ($attributeValue in $attributeValues) { $ADObjectHashTable[$attributeName].Add($attributeValue) } } } else { foreach ($attributeName in $global:ADObjectAttributes) { if (!$AdObject.ContainsKey($attributeName)) { continue } $attributeValues = [System.Collections.ArrayList] $AdObject[$attributeName] $ADObjectHashTable[$attributeName] = New-Object System.Collections.Generic.List[String] foreach ($attributeValue in $attributeValues) { $ADObjectHashTable[$attributeName].Add($attributeValue) } } } Write-Output $ADObjectHashTable } Function Global:ConvertCSObjectToHashTable { param ( [Microsoft.IdentityManagement.PowerShell.ObjectModel.CsObject] [parameter(mandatory=$true)] $CsObject, [string[]] [parameter(mandatory=$true)] $CsObjectAttributes ) $CsObjectHashTable = @{} foreach ($attributeName in $CsObjectAttributes) { if (!$CsObject.Attributes.Contains($attributeName)) { continue } $attributeValues = $CsObject.Attributes[$attributeName].Values $CsObjectHashTable[$attributeName] = New-Object System.Collections.Generic.List[String] foreach ($attributeValue in $attributeValues) { $CsObjectHashTable[$attributeName].Add($attributeValue) } } Write-Output $CsObjectHashTable } Function Global:ConvertMVObjectToHashTable { param ( [Microsoft.IdentityManagement.PowerShell.ObjectModel.MvObject] [parameter(mandatory=$true)] $MvObject ) $MvObjectHashTable = @{} foreach ($attributeName in $global:MvObjectAttributes) { if (!$MvObject.Attributes.Contains($attributeName)) { continue } $attributeValues = $MvObject.Attributes[$attributeName].Values $MvObjectHashTable[$attributeName] = New-Object System.Collections.Generic.List[String] foreach ($attributeValue in $attributeValues) { $MvObjectHashTable[$attributeName].Add($attributeValue) } } Write-Output $MvObjectHashTable } Function Global:ConvertAADUserObjectToHashTable { param ( [Microsoft.Online.Administration.User] [parameter(mandatory=$true)] $AadUserObject ) $AadUserObjectHashTable = @{} if ($AadUserObject.DisplayName) { $AadUserObjectHashTable["DisplayName"] = New-Object System.Collections.Generic.List[String] $AadUserObjectHashTable["DisplayName"].Add($AadUserObject.DisplayName) } if ($AadUserObject.ImmutableId) { $AadUserObjectHashTable["ImmutableId"] = New-Object System.Collections.Generic.List[String] $AadUserObjectHashTable["ImmutableId"].Add($AadUserObject.ImmutableId) } if ($AadUserObject.IsLicensed) { $AadUserObjectHashTable["IsLicensed"] = New-Object System.Collections.Generic.List[String] $AadUserObjectHashTable["IsLicensed"].Add($AadUserObject.IsLicensed) } if ($AadUserObject.LastDirSyncTime) { $AadUserObjectHashTable["LastDirSyncTime"] = New-Object System.Collections.Generic.List[String] $AadUserObjectHashTable["LastDirSyncTime"].Add($AadUserObject.LastDirSyncTime) } if ($AadUserObject.UserPrincipalName) { $AadUserObjectHashTable["UserPrincipalName"] = New-Object System.Collections.Generic.List[String] $AadUserObjectHashTable["UserPrincipalName"].Add($AadUserObject.UserPrincipalName) } if ($AadUserObject.ProxyAddresses) { $AadUserObjectHashTable["ProxyAddresses"] = New-Object System.Collections.Generic.List[String] foreach ($proxyAddress in $AadUserObject.ProxyAddresses) { $AadUserObjectHashTable["ProxyAddresses"].Add($proxyAddress) } } Write-Output $AadUserObjectHashTable } Function Global:ConvertAADContactObjectToHashTable { param ( [Microsoft.Online.Administration.Contact] [parameter(mandatory=$true)] $AadContactObject ) $AadContactObjectHashTable = @{} if ($AadContactObject.DisplayName) { $AadContactObjectHashTable["DisplayName"] = New-Object System.Collections.Generic.List[String] $AadContactObjectHashTable["DisplayName"].Add($AadContactObject.DisplayName) } if ($AadContactObject.ImmutableId) { $AadContactObjectHashTable["ImmutableId"] = New-Object System.Collections.Generic.List[String] $AadContactObjectHashTable["ImmutableId"].Add($AadContactObject.ImmutableId) } if ($AadContactObject.LastDirSyncTime) { $AadContactObjectHashTable["LastDirSyncTime"] = New-Object System.Collections.Generic.List[String] $AadContactObjectHashTable["LastDirSyncTime"].Add($AadContactObject.LastDirSyncTime) } if ($AadContactObject.UserPrincipalName) { $AadContactObjectHashTable["UserPrincipalName"] = New-Object System.Collections.Generic.List[String] $AadContactObjectHashTable["UserPrincipalName"].Add($AadContactObject.UserPrincipalName) } if ($AadContactObject.ProxyAddresses) { $AadContactObjectHashTable["ProxyAddresses"] = New-Object System.Collections.Generic.List[String] foreach ($proxyAddress in $AadContactObject.ProxyAddresses) { $AadContactObjectHashTable["ProxyAddresses"].Add($proxyAddress) } } Write-Output $AadContactObjectHashTable } Function Global:ConvertAADGroupObjectToHashTable { param ( [Microsoft.Online.Administration.Group] [parameter(mandatory=$true)] $AadGroupObject ) $AadGroupObjectHashTable = @{} if ($AadGroupObject.DisplayName) { $AadGroupObjectHashTable["DisplayName"] = New-Object System.Collections.Generic.List[String] $AadGroupObjectHashTable["DisplayName"].Add($AadGroupObject.DisplayName) } if ($AadGroupObject.ImmutableId) { $AadGroupObjectHashTable["ImmutableId"] = New-Object System.Collections.Generic.List[String] $AadGroupObjectHashTable["ImmutableId"].Add($AadGroupObject.ImmutableId) } if ($AadGroupObject.LastDirSyncTime) { $AadGroupObjectHashTable["LastDirSyncTime"] = New-Object System.Collections.Generic.List[String] $AadGroupObjectHashTable["LastDirSyncTime"].Add($AadGroupObject.LastDirSyncTime) } if ($AadGroupObject.ProxyAddresses) { $AadGroupObjectHashTable["ProxyAddresses"] = New-Object System.Collections.Generic.List[String] foreach ($proxyAddress in $AadGroupObject.ProxyAddresses) { $AadGroupObjectHashTable["ProxyAddresses"].Add($proxyAddress) } } Write-Output $AadGroupObjectHashTable } Function ReportOutput { param ( [string] [parameter(mandatory=$false, ValueFromPipeline=$True)] $Output, [string] [parameter(mandatory=$false)] $PropertyName = [string]::Empty, [string] [parameter(mandatory=$false)] $PropertyValue = [string]::Empty ) if ($isNonInteractiveMode) { Write-AscOutput -Message $Output -PropertyName $PropertyName -PropertyValue $PropertyValue -OutputType 'Output' } else { Write-Host $Output -fore Green } } Function ReportError { param ( [string] [parameter(mandatory=$true, ValueFromPipeline=$True)] $ErrorString, [string] [parameter(mandatory=$false)] $PropertyName = [string]::Empty, [string] [parameter(mandatory=$false)] $PropertyValue = [string]::Empty ) if ($isNonInteractiveMode) { Write-AscOutput -Message $ErrorString -PropertyName $PropertyName -PropertyValue $PropertyValue -OutputType 'Error' } else { Write-Host $ErrorString -fore Red } } Function ReportWarning { param ( [string] [parameter(mandatory=$true, ValueFromPipeline=$True)] $WarningString, [string] [parameter(mandatory=$false)] $PropertyName = [string]::Empty, [string] [parameter(mandatory=$false)] $PropertyValue = [string]::Empty ) if ($isNonInteractiveMode) { Write-AscOutput -Message $WarningString -PropertyName $PropertyName -PropertyValue $PropertyValue -OutputType 'Warning' } else { Write-Host $WarningString -fore Cyan } } Function Write-AscOutput { param ( [string] [parameter(mandatory=$false, ValueFromPipeline=$True)] $Message = [string]::Empty, [string] [parameter(mandatory=$false)] $PropertyName = [string]::Empty, [string] [parameter(mandatory=$false)] $PropertyValue = [string]::Empty, [string] [parameter(mandatory=$true)] $OutputType ) $obj = New-Object PSCustomObject -Property @{ $AscCustomScriptObjectProperty = $true PropertyName = $PropertyName PropertyValue = $PropertyValue Message = $Message OutputType = $OutputType } Write-Output $obj } # SIG # Begin signature block # MIInogYJKoZIhvcNAQcCoIInkzCCJ48CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAj37X/gCZTRN9G # Coga+KauNaiZYyma0dopRtmVHVrXJ6CCDYIwggYAMIID6KADAgECAhMzAAADXJXz # SFtKBGrPAAAAAANcMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjMwNDA2MTgyOTIyWhcNMjQwNDAyMTgyOTIyWjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDijA1UCC84R0x+9Vr/vQhPNbfvIOBFfymE+kuP+nho3ixnjyv6vdnUpgmm6RT/ # pL9cXL27zmgVMw7ivmLjR5dIm6qlovdrc5QRrkewnuQHnvhVnLm+pLyIiWp6Tow3 # ZrkoiVdip47m+pOBYlw/vrkb8Pju4XdA48U8okWmqTId2CbZTd8yZbwdHb8lPviE # NMKzQ2bAjytWVEp3y74xc8E4P6hdBRynKGF6vvS6sGB9tBrvu4n9mn7M99rp//7k # ku5t/q3bbMjg/6L6mDePok6Ipb22+9Fzpq5sy+CkJmvCNGPo9U8fA152JPrt14uJ # ffVvbY5i9jrGQTfV+UAQ8ncPAgMBAAGjggF/MIIBezArBgNVHSUEJDAiBgorBgEE # AYI3TBMBBgorBgEEAYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUXgIsrR+tkOQ8 # 10ekOnvvfQDgTHAwRQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEWMBQGA1UEBRMNMjMzMTEwKzUwMDg2ODAfBgNVHSMEGDAWgBRI # bmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEt # MDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIw # MTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBABIm # T2UTYlls5t6i5kWaqI7sEfIKgNquF8Ex9yMEz+QMmc2FjaIF/HQQdpJZaEtDM1Xm # 07VD4JvNJEplZ91A4SIxjHzqgLegfkyc384P7Nn+SJL3XK2FK+VAFxdvZNXcrkt2 # WoAtKo0PclJOmHheHImWSqfCxRispYkKT9w7J/84fidQxSj83NPqoCfUmcy3bWKY # jRZ6PPDXlXERRvl825dXOfmCKGYJXHKyOEcU8/6djs7TDyK0eH9ss4G9mjPnVZzq # Gi/qxxtbddZtkREDd0Acdj947/BTwsYLuQPz7SNNUAmlZOvWALPU7OOVQlEZzO8u # Ec+QH24nep/yhKvFYp4sHtxUKm1ZPV4xdArhzxJGo48Be74kxL7q2AlTyValLV98 # u3FY07rNo4Xg9PMHC6sEAb0tSplojOHFtGtNb0r+sioSttvd8IyaMSfCPwhUxp+B # Td0exzQ1KnRSBOZpxZ8h0HmOlMJOInwFqrCvn5IjrSdjxKa/PzOTFPIYAfMZ4hJn # uKu15EUuv/f0Tmgrlfw+cC0HCz/5WnpWiFso2IPHZyfdbbOXO2EZ9gzB1wmNkbBz # hj8hFyImnycY+94Eo2GLavVTtgBiCcG1ILyQabKDbL7Vh/OearAxcRAmcuVAha07 # WiQx2aLghOSaZzKFOx44LmwUxRuaJ4vO/PRZ7EzAMIIHejCCBWKgAwIBAgIKYQ6Q # 0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT # Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNh # dGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5 # WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQD # Ex9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0B # AQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4 # BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe # 0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato # 88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v # ++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDst # rjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN # 91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4ji # JV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmh # D+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbi # wZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8Hh # hUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaI # jAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTl # UAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNV # HQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQF # TuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29m # dC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNf # MjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5t # aWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNf # MjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcC # ARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnlj # cHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5 # AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oal # mOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0ep # o/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1 # HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtY # SWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInW # H8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZ # iWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMd # YzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7f # QccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKf # enoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOpp # O6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZO # SEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCGXYwghlyAgEBMIGVMH4xCzAJ # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jv # c29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAANclfNIW0oEas8AAAAAA1ww # DQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYK # KwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIJa7XmiD # 0MBcuOi5ImObF7o+imkYAuGPoxYS/eXb9JOWMEIGCisGAQQBgjcCAQwxNDAyoBSA # EgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20w # DQYJKoZIhvcNAQEBBQAEggEAWZFJ6e4YyImdN3j1WYYPr/tOK6T1YWa50VqiYwW/ # 9qm1EfEB3LXbqpEachVEX3S3l63Fno2T/QeaXcuMOFXtczHq0k1MCSZs00u64txR # jw8ny50o+1FoYRa0w+ioHtH8sX5nY0lmi+G8FoC+DjbO9OclJHgAeCChbCLL4A/+ # G/+Aej3MW6yS6+mld5L69J9+erjgm4zaK3XHu4+BeRBeBwKSZ30VPKLSeF8I0PS4 # P2IzV+TsDuMiAUFqXwHoO5/di3NlynjsCMWlSLNIPLDGExKVqUqCDOYnURFzKz40 # 65BcQmc71g++Xf2AuCfXUT5LsXosDmU50u/IrfmfGzuEX6GCFwAwghb8BgorBgEE # AYI3AwMBMYIW7DCCFugGCSqGSIb3DQEHAqCCFtkwghbVAgEDMQ8wDQYJYIZIAWUD # BAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGEWQoD # ATAxMA0GCWCGSAFlAwQCAQUABCB/eJFSidn8hc7HCbj2CpDV7l8KODz0xTi/rpLt # CJlPOAIGZFzvGDIGGBMyMDIzMDUxNzIyNTUyOS45MzVaMASAAgH0oIHQpIHNMIHK # MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk # bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxN # aWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMSYwJAYDVQQLEx1UaGFsZXMgVFNT # IEVTTjo3QkYxLUUzRUEtQjgwODElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3Rh # bXAgU2VydmljZaCCEVcwggcMMIIE9KADAgECAhMzAAAByPmw7mft6mtGAAEAAAHI # MA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n # dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y # YXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4X # DTIyMTEwNDE5MDEzN1oXDTI0MDIwMjE5MDEzN1owgcoxCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNh # IE9wZXJhdGlvbnMxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjdCRjEtRTNFQS1C # ODA4MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjAN # BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAucudfihPgyRWwnnIuJCqc3TCtFk0 # XOimFcKjU9bS6WFng2l+FrIid0mPZ7KWs6Ewj21X+ZkGkM6x+ozHlmNtnHSQ48pj # IFdlKXIoh7fSo41A4n0tQIlwhs8uIYIocp72xwDBHKSZxGaEa/0707iyOw+aXZXN # cTxgNiREASb9thlLZM75mfJIgBVvUmdLZc+XOUYwz/8ul7IEztPNH4cn8Cn0tJhI # Ffp2netr8GYNoiyIqxueG7+sSt2xXl7/igc5cHPZnWhfl9PaB4+SutrA8zAhzVHT # nj4RffxA4R3k4BRbPdGowQfOf95ZeYxLTHf5awB0nqZxOY+yuGWhf6hp5RGRouc9 # beVZv98M1erYa55S1ahZgGDQJycVtEy82RlmKfTYY2uNmlPLWtnD7sDlpVkhYQGK # uTWnuwQKq9ZTSE+0V2cH8JaWBYJQMIuWWM83vLPo3IT/S/5jT2oZOS9nsJgwwCwR # UtYtwtq8/PJtvt1V6VoG4Wd2/MAifgEJOkHF7ARPqI9Xv28+riqJZ5mjLGz84dP2 # ryoe0lxYSz3PT5ErKoS0+zJpYNAcxbv2UXiTk3Wj/mZ3tulz6z4XnSl5gy0PLer+ # EVjz4G96GcZgK2d9G+uYylHWwBneIv9YFQj6yMdW/4sEpkEbrpiJNemcxUCmBipZ # 7Sc35rv4utkJ4/UCAwEAAaOCATYwggEyMB0GA1UdDgQWBBS1XC9JgbrSwLDTiJJT # 4iK7NUvk9TAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNVHR8E # WDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9N # aWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYIKwYB # BQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20v # cGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEw # KDEpLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqG # SIb3DQEBCwUAA4ICAQDD1nJSyEPDqSgnfkFifIbteJb7NkZCbRj5yBGiT1f9fTGv # Ub5CW7k3eSp3uxUqom9LWykcNfQa/Yfw0libEim9YRjUNcL42oIFqtp/7rl9gg61 # oiB8PB+6vLEmjXkYxUUR8WjKKC5Q5dx96B21faSco2MOmvjYxGUR7An+4529lQPP # LqbEKRjcNQb+p+mkQH2XeMbsh5EQCkTuYAimFTgnui2ZPFLEuBpxBK5z2HnKneHU # J9i4pcKWdCqF1AOVN8gXIH0R0FflMcCg5TW8v90Vwx/mP3aE2Ige1uE8M9YNBn57 # 76PxmA16Z+c2s+hYI+9sJZhhRA8aSYacrlLz7aU/56OvEYRERQZttuAFkrV+M/J+ # tCeGNv0Gd75Y4lKLMp5/0xoOviPBdB2rD5C/U+B8qt1bBqQLVZ1wHRy0/6HhJxbO # i2IgGJaOCYLGX2zz0VAT6mZ2BTWrJmcK6SDv7rX7psgC+Cf1t0R1aWCkCHJtpYuy # Kjf7UodRazevOf6V01XkrARHKrI7bQoHFL+sun2liJCBjN51mDWoEgUCEvwB3l+R # FYAL0aIisc5cTaGX/T8F+iAbz+j2GGVum85gEQS9uLzSedoYPyEXxTblwewGdAxq # IZaKozRBow49OnL+5CgooVMf3ZSqpxc2QC0E03l6c/vChkYyqMXq7Lwd4PnHqjCC # B3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZIhvcNAQELBQAw # gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMT # KU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTIx # MDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAg # UENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDk4aZM57Ry # IQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25PhdgM/9cT8dm95VT # cVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPFdvWGUNzBRMhx # XFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6GnszrYBbfowQ # HJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBpDco2LXCOMcg1 # KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50ZuyjLVwIYwXE8s # 4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3EXzTdEonW/aUg # fX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0lBw0gg/wEPK3 # Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1qGFphAXPKZ6Je # 1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ+QuJYfM2BjUY # hEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PAPBXbGjfHCBUY # P3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkwEgYJKwYBBAGC # NxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxGNSnPEP8vBO4w # HQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARVMFMwUQYMKwYB # BAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNv # bS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAKBggrBgEFBQcD # CDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0T # AQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNV # HR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9w # cm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEE # TjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2Nl # cnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG9w0BAQsFAAOC # AgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0xM7U518JxNj/a # ZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmCVgADsAW+iehp # 4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449xvNo32X2pFaq # 95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wMnosZiefwC2qB # woEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDSPeZKPmY7T7uG # +jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2dY3RILLFORy3B # FARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxnGSgkujhLmm77 # IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+CrvsQWY9af3LwUFJ # fn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokLjzbaukz5m/8K # 6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL6Xu/OHBE0ZDx # yKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggLOMIICNwIBATCB # +KGB0KSBzTCByjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO # BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEl # MCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEmMCQGA1UECxMd # VGhhbGVzIFRTUyBFU046N0JGMS1FM0VBLUI4MDgxJTAjBgNVBAMTHE1pY3Jvc29m # dCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoBATAHBgUrDgMCGgMVAN/OE1C7xjU0ClID # XQBiucAY7suyoIGDMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw # b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAw # DQYJKoZIhvcNAQEFBQACBQDoD1Z1MCIYDzIwMjMwNTE3MjEzNDQ1WhgPMjAyMzA1 # MTgyMTM0NDVaMHcwPQYKKwYBBAGEWQoEATEvMC0wCgIFAOgPVnUCAQAwCgIBAAIC # C8sCAf8wBwIBAAICFBswCgIFAOgQp/UCAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYK # KwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQUF # AAOBgQCZ+wVHvtUgRgs4yZzaP8+EfMg/k2Qzg/z9T2IoeT3GHW9va/ZoPYB663wk # clhsYStL/tVZdDYWyI7E1vEOiAD4nWoXpXiIg1CpKEq4Gafsk/ktVYND8o9EZv8R # Y3b/BLuhlgC+npH3kEDwrO1tlmx4VoI3Hc+hEceHtsDVqcQRiDGCBA0wggQJAgEB # MIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV # BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAByPmw7mft6mtG # AAEAAAHIMA0GCWCGSAFlAwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcN # AQkQAQQwLwYJKoZIhvcNAQkEMSIEIIAE86OqimRfPNS+SNt41uir2tF2d8V7vFXG # L/HfwzcMMIH6BgsqhkiG9w0BCRACLzGB6jCB5zCB5DCBvQQgYgCYz80/baMvxw6j # cqSvL0FW4TdvA09nxHfsPhuEA2YwgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFt # cCBQQ0EgMjAxMAITMwAAAcj5sO5n7eprRgABAAAByDAiBCCYz2zh+m6XI7lMnMCW # XJuCdCC1yLSSA61OtEJ8Tz/bhzANBgkqhkiG9w0BAQsFAASCAgASRbgn28mJzIAy # sixVtSKewJh6FgK2KU9S9U0Gaw0Uu2++Zxhubxa+4TfmGunL3Y6PuhxvtcyptvHz # XETtLCAOe4QHVK6bk+WV48krfgZ/DcENq39K1hUGH/9oVyPYuhwxZdMQVhXvrkcS # bAFNcImY9fgnJUOM1mpgu9w5Y7k7zNosmyhTktppyuv4V+UYyZp9b5lMlGNs6iu0 # ZEDztV/Y2I5PDxU4CJ7mIt78UdSy7907u9yIbqy7WlR5/WTWe5wv4K9PMYKfbSb4 # kZnGsB14FxUpDt8Qn3P3FZDbNRm5qhNB9Hhc/CvE1btJSZjIFbKNxAOVCQUnBbnN # X5FIwpPQw6l491Nhs8r5kcIgk1f1DpHdnte4FfF2sOJgGWZaKDgQjwSAXCjKXT4Y # swMpvKGVCblz6po6k4kb/yHHHN2IKJicUp3T58KG7qgV7aPbvz6rO+VqRl09vWZE # bLo2GXinh4ts2DhbXp8YHgmFLZYEu+0VmMYlRAcKi0eGKoTTok3XWGcY4f2pk07O # 2XgUwr2I1RD2AEJkzCbUiKSr3v497PECVc5zkBGRtovcSy+JDQmQt778cNwAW0As # /fWsU+I0Pkj5vc3JXS0nsZ3bYU4YcQKQ1E3sEdZ/DiBR+ELyDLZuhjnLHhEue9Bx # Ey59tg6ug70E3MYHGeI9dNOn5B0sMA== # SIG # End signature block |