Private/Get-ADFSTkIssuanceTransformRules.ps1

function Get-ADFSTkIssuanceTransformRules
{
param (

    [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
    [string[]]$EntityCategories,
    [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=1)]
    [string]$EntityId,
    [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=2)]
    $RequestedAttribute,
    [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=3)]
    $RegistrationAuthority,
    [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=4)]
    $NameIDFormat
)

if ([string]::IsNullOrEmpty($Global:ADFSTkAllAttributes) -or $Global:ADFSTkAllAttributes.Count -eq 0)
{
    $Global:ADFSTkAllAttributes = Import-ADFSTkAllAttributes
}

if ([string]::IsNullOrEmpty($Global:ADFSTkAllTransformRules) -or $Global:ADFSTkAllTransformRules.Count -eq 0)
{
    $Global:ADFSTkAllTransformRules = Import-ADFSTkAllTransformRules
}

if ([string]::IsNullOrEmpty($AllTransformRules))
{
    $AllTransformRules = $Global:ADFSTkAllTransformRules #So we don't need to change anything in the Get-ADFSTkManualSPSettings files
}

$RequestedAttributes = @{}

if (![string]::IsNullOrEmpty($RequestedAttribute))
{
    $RequestedAttribute | % {
        $RequestedAttributes.($_.Name.trimEnd()) = $_.friendlyName
    }
}
else
{
    Write-ADFSTkLog (Get-ADFSTkLanguageText rulesNoRequestedAttributesDetected)
}

$IssuanceTransformRuleCategories = Import-ADFSTkIssuanceTransformRuleCategories -RequestedAttributes $RequestedAttributes

$adfstkConfig = Get-ADFSTkConfiguration

$federationDir = Join-Path $Global:ADFSTkPaths.federationDir $adfstkConfig.FederationConfig.Federation.FederationName
$fedEntityCategoryFileName = Join-Path $federationDir "$($adfstkConfig.FederationConfig.Federation.FederationName)_entityCategories.ps1"

if (Test-Path $fedEntityCategoryFileName)
{
    try {
        Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText rulesFederationEntityCategoryFile)
        . $fedEntityCategoryFileName

        if (Test-Path function:Import-ADFSTkIssuanceTransformRuleCategoriesFromFederation)
        {
            $IssuanceTransformRuleCategoriesFromFederation = Import-ADFSTkIssuanceTransformRuleCategoriesFromFederation -RequestedAttributes $RequestedAttributes
            Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText rulesFederationEntityCategoriesFound -f $IssuanceTransformRuleCategoriesFromFederation.Count)

            foreach ($entityCategory in $IssuanceTransformRuleCategoriesFromFederation.Keys)
            {
                #Add or replace the standard Entoty Category with the federation one
                if ($IssuanceTransformRuleCategories.ContainsKey($entityCategory))
                {
                    Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText rulesFederationEntityCategoryOverwrite -f $entityCategory)
                }
                else
                {
                    Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText rulesFederationEntityCategoryAdd -f $entityCategory)
                }

                $IssuanceTransformRuleCategories.$entityCategory = $IssuanceTransformRuleCategoriesFromFederation.$entityCategory
            }
        }
        else
        {
            #Write Verbose
        }
    }
    catch
    {
        Write-ADFSTkLog (Get-ADFSTkLanguageText rulesFederationEntityCategoryLoadFail) -EntryType Error
    }
}
else
{
    #Write Verbose
}


if ([string]::IsNullOrEmpty($Global:ADFSTkManualSPSettings))
{
    $Global:ADFSTkManualSPSettings = Get-ADFSTkManualSPSettings
}

### Transform Entity Categories

$TransformedEntityCategories = @()

$AttributesFromStore = @{}
$IssuanceTransformRules = [Ordered]@{}

$ManualSPTransformRules = $null

#Check version of get-ADFSTkLocalManualSpSettings and retrieve the transform rules
if ($EntityId -ne $null -and $Global:ADFSTkManualSPSettings.ContainsKey($EntityId))
{
    if ($Global:ADFSTkManualSPSettings.$EntityId -is [System.Collections.Hashtable] -and `
        $Global:ADFSTkManualSPSettings.$EntityId.ContainsKey('TransformRules'))
    {
        $ManualSPTransformRules = $Global:ADFSTkManualSPSettings.$EntityId.TransformRules
    }
    elseif ($Global:ADFSTkManualSPSettings.$EntityId -is [System.Collections.Specialized.OrderedDictionary])
    {
        $ManualSPTransformRules = $Global:ADFSTkManualSPSettings.$EntityId
    }
    else
    {
        #Shouldn't be here
    }
}

#Add manually added entity categories if any

if ($EntityId -ne $null -and `
    $Global:ADFSTkManualSPSettings.ContainsKey($EntityId) -and `
    $Global:ADFSTkManualSPSettings.$EntityId -is [System.Collections.Hashtable] -and `
    $Global:ADFSTkManualSPSettings.$EntityId.ContainsKey('EntityCategories'))
{
    $EntityCategories += $Global:ADFSTkManualSPSettings.$EntityId.EntityCategories
}


if ($EntityCategories -eq $null)
{
    $TransformedEntityCategories += "NoEntityCategory"
}
else
{
    foreach ($entityCategory in $IssuanceTransformRuleCategories.Keys)
    {
        if ($entityCategory -eq "http://www.swamid.se/category/research-and-education" -and $EntityCategories.Contains($entityCategory))
        {
            if ($EntityCategories.Contains("http://www.swamid.se/category/eu-adequate-protection") -or `
                $EntityCategories.Contains("http://www.swamid.se/category/nren-service") -or `
                $EntityCategories.Contains("http://www.swamid.se/category/hei-service"))
            {
                $TransformedEntityCategories += $entityCategory
            }
        }
        elseif ($EntityCategories.Contains($entityCategory)) 
        {
            $TransformedEntityCategories += $entityCategory
        }
    }

    if ($TransformedEntityCategories.Count -eq 0)
    {
        $TransformedEntityCategories += "NoEntityCategory"
    }

###

}

#region Add TransformRules from categories
$TransformedEntityCategories | % { 

    if ($_ -ne $null -and $IssuanceTransformRuleCategories.ContainsKey($_))
    {
        foreach ($Rule in $IssuanceTransformRuleCategories[$_].Keys) { 
            if ($IssuanceTransformRuleCategories[$_][$Rule] -ne $null)
            {
                $IssuanceTransformRules[$Rule] = Get-ADFSTkEnhancedRule -Rule $IssuanceTransformRuleCategories[$_][$Rule] -EntityId $EntityId
                foreach ($Attribute in $IssuanceTransformRuleCategories[$_][$Rule].Attribute) { 
                    $AttributesFromStore[$Attribute] = $Global:ADFSTkAllAttributes[$Attribute]
                }
            }
        }
    }
}
#endregion

#AllSPs
if ($Global:ADFSTkManualSPSettings.ContainsKey('urn:adfstk:allsps'))
{
    foreach ($Rule in $Global:ADFSTkManualSPSettings['urn:adfstk:allsps'].TransformRules.Keys) { 
        if ($Global:ADFSTkManualSPSettings['urn:adfstk:allsps'].TransformRules[$Rule] -ne $null)
        {                
            $IssuanceTransformRules[$Rule] = Get-ADFSTkEnhancedRule -Rule $Global:ADFSTkManualSPSettings['urn:adfstk:allsps'].TransformRules[$Rule] -EntityId $EntityId
            foreach ($Attribute in $Global:ADFSTkManualSPSettings['urn:adfstk:allsps'].TransformRules[$Rule].Attribute) { 
                $AttributesFromStore[$Attribute] = $Global:ADFSTkAllAttributes[$Attribute]
            }
        }
    }
}

#AllEduSPs

if ($EntityId -ne $null)
{
    
    #First remove http:// or https://
    $entityDNS = $EntityId.ToLower().Replace('http://','').Replace('https://','')

    #Second get rid of all ending sub paths
    $entityDNS = $entityDNS -split '/' | select -First 1

    #Last fetch the last two words and join them with a .
    #$entityDNS = ($entityDNS -split '\.' | select -Last 2) -join '.'

    $settingsDNS = $null

    foreach($setting in $Global:ADFSTkManualSPSettings.Keys)
    {
        if ($setting.StartsWith('urn:adfstk:entityiddnsendswith:'))
        {
            $settingsDNS = $setting -split ':' | select -Last 1
        }
    }

    if ($entityDNS.EndsWith($settingsDNS) -and `
        $Global:ADFSTkManualSPSettings."urn:adfstk:entityiddnsendswith:$settingsDNS" -is [System.Collections.Hashtable] -and `
        $Global:ADFSTkManualSPSettings."urn:adfstk:entityiddnsendswith:$settingsDNS".ContainsKey('TransformRules'))
    {
        foreach ($Rule in $Global:ADFSTkManualSPSettings["urn:adfstk:entityiddnsendswith:$settingsDNS"].TransformRules.Keys) { 
            if ($Global:ADFSTkManualSPSettings["urn:adfstk:entityiddnsendswith:$settingsDNS"].TransformRules[$Rule] -ne $null)
            {                
                $IssuanceTransformRules[$Rule] = Get-ADFSTkEnhancedRule -Rule $Global:ADFSTkManualSPSettings["urn:adfstk:entityiddnsendswith:$settingsDNS"].TransformRules[$Rule] -EntityId $EntityId
                foreach ($Attribute in $Global:ADFSTkManualSPSettings["urn:adfstk:entityiddnsendswith:$settingsDNS"].TransformRules[$Rule].Attribute) { 
                    $AttributesFromStore[$Attribute] = $Global:ADFSTkAllAttributes[$Attribute]
                }
            }
        }
    }
}


#Manual SP
if ($ManualSPTransformRules -ne $null)
{
    foreach ($Rule in $ManualSPTransformRules.Keys) { 
        if ($ManualSPTransformRules[$Rule] -ne $null)
        {                
            $IssuanceTransformRules[$Rule] = Get-ADFSTkEnhancedRule -Rule $ManualSPTransformRules[$Rule] -EntityId $EntityId
            foreach ($Attribute in $ManualSPTransformRules[$Rule].Attribute) { 
                $AttributesFromStore[$Attribute] = $Global:ADFSTkAllAttributes[$Attribute]
            }
        }
    }
}

#region Add NameID to TransformRules
#first check if we already has a NameID in the rules
if ([string]::IsNullOrEmpty($IssuanceTransformRules.'transient-id') -and [string]::IsNullOrEmpty($IssuanceTransformRules.'persistent-id') -and [string]::IsNullOrEmpty($IssuanceTransformRules.'eduPersonTargetedID'))
{
    if ([string]::IsNullOrEmpty($NameIDFormat))
    {
        $IssuanceTransformRules.'transient-id' = Get-ADFSTkEnhancedRule -Rule $Global:ADFSTkAllTransformRules.'transient-id' -EntityId $EntityId
        foreach ($Attribute in $Global:ADFSTkAllTransformRules.'transient-id'.Attribute) { 
            $AttributesFromStore[$Attribute] = $Global:ADFSTkAllAttributes[$Attribute]
        }
    }
    elseif ($NameIDFormat.Contains('urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'))
    {
        $IssuanceTransformRules.'persistent-id' = Get-ADFSTkEnhancedRule -Rule $Global:ADFSTkAllTransformRules.'persistent-id' -EntityId $EntityId
        foreach ($Attribute in $Global:ADFSTkAllTransformRules.'persistent-id'.Attribute) { 
            $AttributesFromStore[$Attribute] = $Global:ADFSTkAllAttributes[$Attribute]
        }
    }
    else
    {
        $IssuanceTransformRules.'transient-id' = Get-ADFSTkEnhancedRule -Rule $Global:ADFSTkAllTransformRules.'transient-id' -EntityId $EntityId
        foreach ($Attribute in $Global:ADFSTkAllTransformRules.'transient-id'.Attribute) { 
            $AttributesFromStore[$Attribute] = $Global:ADFSTkAllAttributes[$Attribute]
        }
    }
}
#endregion

### This is a good place to remove attributes that shouldn't be sent outside a RegistrationAuthority
$removeRules = @()
foreach ($attr in $AttributesFromStore.values)
{
    $attribute = $Settings.configuration.attributes.attribute | ? type -eq $attr.type
    if ($attribute -ne $null -and $attribute.allowedRegistrationAuthorities -ne $null)
    {
        $allowedRegistrationAuthorities = @()
        $allowedRegistrationAuthorities += $attribute.allowedRegistrationAuthorities.registrationAuthority
        if ($allowedRegistrationAuthorities.count -gt 0 -and !$allowedRegistrationAuthorities.contains($RegistrationAuthority))
        {
            $removeRules += $attr
        }
    }
}

$removeRules | % {
    
    $AttributesFromStore.Remove($_.type)
    foreach ($key in $Global:ADFSTkAllTransformRules.Keys) 
    {
        if ($Global:ADFSTkAllTransformRules.$key.Attribute -eq $_.type) 
        {

            $currentStoreAttributes = $AttributesFromStore.Values | ? store -eq $store.name
            if ($currentStoreAttributes.Count -ne $null)
            {
                $FirstRule += @"
 
                @RuleName = "Retrieve Attributes from AD"
                c:[Type == "$($store.type)", Issuer == "$($store.issuer)"]
                => add(store = "$($store.name)",
                types = ("$($currentStoreAttributes.type -join '","')"),
                query = ";$($currentStoreAttributes.name -join ',');{0}", param = c.Value);
 
"@

            }

            $IssuanceTransformRules.Remove($key)
            break

        }
    }
}


###

#region Create Stores
if ($AttributesFromStore.Count -ne $null)
{

    $FirstRule = Get-ADFSTkStoreRule -Stores $Settings.configuration.storeConfig.stores.store `
                                     -AttributesFromStore $AttributesFromStore `
                                     -EntityId $EntityId 

    return  $FirstRule + $IssuanceTransformRules.Values
}
else
{
    return $IssuanceTransformRules.Values
}
#endregion
}
# SIG # Begin signature block
# MIIjnwYJKoZIhvcNAQcCoIIjkDCCI4wCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAdLQ/KkGAZqJcN
# 7eP2H0eBmE8sA3W+/ijDmJ+Qp6eB6qCCHZgwggT+MIID5qADAgECAhANQkrgvjqI
# /2BAIc4UAPDdMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV
# BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0EwHhcN
# MjEwMTAxMDAwMDAwWhcNMzEwMTA2MDAwMDAwWjBIMQswCQYDVQQGEwJVUzEXMBUG
# A1UEChMORGlnaUNlcnQsIEluYy4xIDAeBgNVBAMTF0RpZ2lDZXJ0IFRpbWVzdGFt
# cCAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwuZhhGfFivUN
# CKRFymNrUdc6EUK9CnV1TZS0DFC1JhD+HchvkWsMlucaXEjvROW/m2HNFZFiWrj/
# ZwucY/02aoH6KfjdK3CF3gIY83htvH35x20JPb5qdofpir34hF0edsnkxnZ2OlPR
# 0dNaNo/Go+EvGzq3YdZz7E5tM4p8XUUtS7FQ5kE6N1aG3JMjjfdQJehk5t3Tjy9X
# tYcg6w6OLNUj2vRNeEbjA4MxKUpcDDGKSoyIxfcwWvkUrxVfbENJCf0mI1P2jWPo
# GqtbsR0wwptpgrTb/FZUvB+hh6u+elsKIC9LCcmVp42y+tZji06lchzun3oBc/gZ
# 1v4NSYS9AQIDAQABo4IBuDCCAbQwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQC
# MAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwQQYDVR0gBDowODA2BglghkgBhv1s
# BwEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMB8G
# A1UdIwQYMBaAFPS24SAd/imu0uRhpbKiJbLIFzVuMB0GA1UdDgQWBBQ2RIaOpLqw
# Zr68KC0dRDbd42p6vDBxBgNVHR8EajBoMDKgMKAuhixodHRwOi8vY3JsMy5kaWdp
# Y2VydC5jb20vc2hhMi1hc3N1cmVkLXRzLmNybDAyoDCgLoYsaHR0cDovL2NybDQu
# ZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC10cy5jcmwwgYUGCCsGAQUFBwEBBHkw
# dzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tME8GCCsGAQUF
# BzAChkNodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyQXNz
# dXJlZElEVGltZXN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQBIHNy1
# 6ZojvOca5yAOjmdG/UJyUXQKI0ejq5LSJcRwWb4UoOUngaVNFBUZB3nw0QTDhtk7
# vf5EAmZN7WmkD/a4cM9i6PVRSnh5Nnont/PnUp+Tp+1DnnvntN1BIon7h6JGA078
# 9P63ZHdjXyNSaYOC+hpT7ZDMjaEXcw3082U5cEvznNZ6e9oMvD0y0BvL9WH8dQgA
# dryBDvjA4VzPxBFy5xtkSdgimnUVQvUtMjiB2vRgorq0Uvtc4GEkJU+y38kpqHND
# Udq9Y9YfW5v3LhtPEx33Sg1xfpe39D+E68Hjo0mh+s6nv1bPull2YYlffqe0jmd4
# +TaY4cso2luHpoovMIIFMTCCBBmgAwIBAgIQCqEl1tYyG35B5AXaNpfCFTANBgkq
# hkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBB
# c3N1cmVkIElEIFJvb3QgQ0EwHhcNMTYwMTA3MTIwMDAwWhcNMzEwMTA3MTIwMDAw
# WjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
# ExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3Vy
# ZWQgSUQgVGltZXN0YW1waW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
# CgKCAQEAvdAy7kvNj3/dqbqCmcU5VChXtiNKxA4HRTNREH3Q+X1NaH7ntqD0jbOI
# 5Je/YyGQmL8TvFfTw+F+CNZqFAA49y4eO+7MpvYyWf5fZT/gm+vjRkcGGlV+Cyd+
# wKL1oODeIj8O/36V+/OjuiI+GKwR5PCZA207hXwJ0+5dyJoLVOOoCXFr4M8iEA91
# z3FyTgqt30A6XLdR4aF5FMZNJCMwXbzsPGBqrC8HzP3w6kfZiFBe/WZuVmEnKYmE
# UeaC50ZQ/ZQqLKfkdT66mA+Ef58xFNat1fJky3seBdCEGXIX8RcG7z3N1k3vBkL9
# olMqT4UdxB08r8/arBD13ays6Vb/kwIDAQABo4IBzjCCAcowHQYDVR0OBBYEFPS2
# 4SAd/imu0uRhpbKiJbLIFzVuMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3z
# bcgPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQM
# MAoGCCsGAQUFBwMIMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDov
# L29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5k
# aWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MIGBBgNVHR8E
# ejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1
# cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v
# RGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMFAGA1UdIARJMEcwOAYKYIZIAYb9
# bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT
# MAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAQEAcZUS6VGHVmnN793afKpj
# erN4zwY3QITvS4S/ys8DAv3Fp8MOIEIsr3fzKx8MIVoqtwU0HWqumfgnoma/Capg
# 33akOpMP+LLR2HwZYuhegiUexLoceywh4tZbLBQ1QwRostt1AuByx5jWPGTlH0gQ
# GF+JOGFNYkYkh2OMkVIsrymJ5Xgf1gsUpYDXEkdws3XVk4WTfraSZ/tTYYmo9WuW
# wPRYaQ18yAGxuSh1t5ljhSKMYcp5lH5Z/IwP42+1ASa2bKXuh1Eh5Fhgm7oMLStt
# osR+u8QlK0cCCHxJrhO24XxCQijGGFbPQTS2Zl22dHv1VjMiLyI2skuiSpXY9aaO
# UjCCBd8wggTHoAMCAQICEE5A5DdU7eaMAAAAAFHTlH8wDQYJKoZIhvcNAQELBQAw
# gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL
# Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg
# MjAwOSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw
# BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
# MB4XDTIxMDUwNzE1NDM0NVoXDTMwMTEwNzE2MTM0NVowaTELMAkGA1UEBhMCVVMx
# FjAUBgNVBAoMDUVudHJ1c3QsIEluYy4xQjBABgNVBAMMOUVudHJ1c3QgQ29kZSBT
# aWduaW5nIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBDU0JSMTCCAiIw
# DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKeBj/cURbZiQ/LYrtMlXkhPUb/F
# fZ9QHDXR1n5hKpQZbSdGpKYaXfdUUWqAIsaoZnVNVIPJXmgbq/ZbZLCtrSC9VO9G
# a20C50WudfaOirkyLou4dxxSTXmIX6U6GMlQLJcnLb/aAH1jf+8y7EaHY9uan8Na
# ITZ7+ZvVyqBuciz84fGecE0IVhVvkKv7SLq518GCeIVlLn+1ycDiFLc3EUEG4org
# qPblfrZ4BQHDYO1PB0EuChNJ45Cbf929+qy/ZFHRXJu09VznXP87m6WgGtd9CbLC
# t/9uHLzIfebpK/xysxTpSlUShJxEJXUd9irwT6UgPWgl62GXfA/ltj3zrsPBEbwb
# jszgRzBeQgCGceNYrAbKZR97lKZLV2cMfl6teGdbVeNe68fY7Exuhsvz3Pifh6py
# WBIPfab4+EI5Ozws5DJNSYzg4QDCOKCc+oQ+QdxuVq7GGlv0Z2gFAc0bv66HvJ1T
# 9i7otmvkmd7FT4dYqNJlHsgf1XJu7lkcVzsJcp3XyreQxs17RZKRQgNMfT/K8qq4
# wg6G8xCfRi6kZoZoWmgYcCk4EYBga4pDo3Ns47NrN//mnWcBkobfL0jR+1Bg1Vz+
# IdMBQmP+73C0F8CPqO7TwUtfEur9/S4Oh0Rg46n0whij4/3ODIQiDfOneNqT89s4
# z7kvM8b/BzxevkXTAgMBAAGjggErMIIBJzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0T
# AQH/BAgwBgEB/wIBATAdBgNVHSUEFjAUBggrBgEFBQcDAwYIKwYBBQUHAwgwOwYD
# VR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cuZW50cnVz
# dC5uZXQvcnBhMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29j
# c3AuZW50cnVzdC5uZXQwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL2NybC5lbnRy
# dXN0Lm5ldC9nMmNhLmNybDAdBgNVHQ4EFgQUgrrWPZfOn89x6JI3r/2ztWk1V88w
# HwYDVR0jBBgwFoAUanImetAe733nO2lR1GyNn5ASZqswDQYJKoZIhvcNAQELBQAD
# ggEBAB9eQQS2g3AkUyxVcx1lOsDstHsEmF5ZOBMJpFmUQl5Qv09sbiUgkJNYQA31
# GbRi7iRewgFYFQIdEAlvqNT7kn43OD4vFH2PHUM2ZLNmE18UzKVx91shS8aXvtyV
# /HB9ERzTId3QJDkpxf4KGqXPe3nuOm/e3L/pEd0WgwjTLI1/TagUeS8FYVI462Dz
# FGh9y7KKrcCUXOQmDiyK3UbDzuRWUcVW44W4TZtFcosH8Yr7Sbhf0fKWgV1pUiTx
# CCPS1iMP64vXfovBk2v68WJ7WOlQm5duF4gN4cZDmNeBYbaFnUfssZ6uPyA7Q53Y
# ohzg1HwIwq92BvhiZnq29/rIrzUwggaDMIIEa6ADAgECAhA1r7d7nTQfavyPhEar
# MTUrMA0GCSqGSIb3DQEBDQUAMGkxCzAJBgNVBAYTAlVTMRYwFAYDVQQKDA1FbnRy
# dXN0LCBJbmMuMUIwQAYDVQQDDDlFbnRydXN0IENvZGUgU2lnbmluZyBSb290IENl
# cnRpZmljYXRpb24gQXV0aG9yaXR5IC0gQ1NCUjEwHhcNMjEwNTA3MTkxOTUyWhcN
# NDAxMjI5MjM1OTAwWjBjMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNRW50cnVzdCwg
# SW5jLjE8MDoGA1UEAxMzRW50cnVzdCBFeHRlbmRlZCBWYWxpZGF0aW9uIENvZGUg
# U2lnbmluZyBDQSAtIEVWQ1MyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
# AgEAvr2nOcmlfexdZfH0K6mH0OetGsUaOxjO4aFRjXL6zlgfXLgkQg9G1TGX0EpN
# 45swybqXqJz+RTbPJ4Dne7huwSS336d03IXyoyRYRcyUlDsC68SNfEb1XGaC46TB
# 0x+sbgxTIw7UOvraQvGDVF81MlbytXibVwBIHqlhYScOcwNDttZwkvvUhZowxrPm
# ml5L7x0q2GarFkb/C9gPpolKAlFXQTxBOE6Xx1EybWeOZqFeTZ81Iq/Vard/QF9o
# Ncxp+vEF8OqFpuoyhcvBwcqDaUVJBtwJbLpJZRmM+bc3J4xknjXj5eznB6CdqHK8
# b4U6LKYWTj2czwjmgvVEfSjAvYmtbC/cL3h5EdcccEvdnQhMXi76jb2n3WP2f/BS
# MYRuOtjZXIVEnmMGadCGWHiJm4e7WBykKGzG/mkKnB6sEWBqXslpZS7tQy1p8Xi3
# Oy018qpP4h/jAW+QRqrVqA0EV6C0rONtvZ0bKIAnRsfaqmeV8dGHe8fIJemEDI+J
# NtK+M+GFwDPVoDwZi6848uWTgL/Gw6t7k8Q9nbnuRXbA1GhvMF48tDb510VC4BIG
# gNulIfznBXoojbSOYHv3yLVKR6wUZpegWmlyMVdrU4TNYbpzBxVwO3sB/Kc/jC09
# h4z7CNflLxeDfoKrTwnyKeF+VXdllAUdWdQK3ZN+4xRd4rsCAwEAAaOCASswggEn
# MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFM6JT4JRqhWihGLKMSNh0mH7
# +P54MB8GA1UdIwQYMBaAFIK61j2Xzp/PceiSN6/9s7VpNVfPMDMGCCsGAQUFBwEB
# BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5uZXQwMQYDVR0f
# BCowKDAmoCSgIoYgaHR0cDovL2NybC5lbnRydXN0Lm5ldC9jc2JyMS5jcmwwDgYD
# VR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMEQGA1UdIAQ9MDswMAYE
# VR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L3JwYTAH
# BgVngQwBAzANBgkqhkiG9w0BAQ0FAAOCAgEAPgBUuCrzj2avYRbEWJNk9EGLZFWN
# GzUzoZuR2KtGyqtfvL5+cOTS1weolgfXhtFXCgjQ0HhN+CrfsgTzmuHXfPDBAHrB
# QKHfioy3y7QdAWHymJqm3biDBcqpLBbcnC0O/qeX5FCpl5XBSyqMUePEAuBrfDVN
# U7xLlBOLUxgWXqYKp7g0wWyx6yzkMX0MLMZ84aRW6C121bITdeqDAK4Ad8ZvqT3u
# YxSBUBb8W08SGQ5bD43qS84GTIlLriDMjkemddZl7i8w6F00jx+CTVxCpvIUTFAg
# nAmidCRcOdiJMoU8r4zlap7mBDqlE/+qHc1HSy4CBbRqj+uFT4HvCtt9nymPpcI/
# UjhSQZU7vD5bVDBCIwlj3lCNiTVF+qu4D4+irXt6EZPxjyiEe2h5R2roZClNH/Qd
# L20eyJSGPNNamXprfKs19ys5S0+5PxaS7ymMjausARrMcUQ5y0A+IBLOCHDjR/7c
# gNcIANELauohtXlmF+lqqlbdzRV4sQPAFK0+Rxh17QpTSzKTzf+AsZDWE+XkQXgi
# 7UGC5Q7fsM6VIUXmiwHTGff0K1Ws2VZzYxDguKBty1SWmKCZIVEGqqYMOitjy3na
# Q7nSEszej1V66Qnz4prTJcF7NpLa4OVSZ83j5lQKpZ3Uc6PTL10GZIUDd39g2MK8
# dMmVkWi3t35hGXUwggbzMIIE26ADAgECAhAWdy8OxRnHb5IdXyBiye3RMA0GCSqG
# SIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
# MTwwOgYDVQQDEzNFbnRydXN0IEV4dGVuZGVkIFZhbGlkYXRpb24gQ29kZSBTaWdu
# aW5nIENBIC0gRVZDUzIwHhcNMjIwMzI5MjAxODAzWhcNMjMwMzI5MjAxODAzWjCB
# ozELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xDzANBgNVBAcTBk90dGF3
# YTETMBEGCysGAQQBgjc8AgEDEwJDQTEUMBIGA1UEChMLQ0FOQVJJRSBJTkMxHTAb
# BgNVBA8TFFByaXZhdGUgT3JnYW5pemF0aW9uMREwDwYDVQQFEwgyOTAyMDgtNzEU
# MBIGA1UEAxMLQ0FOQVJJRSBJTkMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
# AoICAQC7QrVGr/0GFSjOKBtAIfg420mYYBtsT/eqfZigZeS4ZW6sykAZBX71qiU+
# 1SqfMpfU+GY2oQAvGGq/1kBaKTukhT+wwEAH90wJeaMSzAhpl9Q8vSx0xRfXmKfx
# GG8cn6kuq9DZb9kKeKP2qWSFPJyS2y0F5pVhSp8hDvZxAeAKNAjoTDip55kMJm14
# /CkqU2biZ35prXMDMh7/29YWuFWX55zKOxEfVWbbsRKGladcYtKXu1oqSh0XEhhF
# B1BLXBw1YdN2RgjXAIMxrsvNjQ7q8ZWHEMrgvA/50X59x9vxQLS4ivT8RRLic+EW
# 6BMoQ7tqlUwedFSLRsGRxs+7tLwt0FYjQQEYZEbqUpLCcrdco9QEWSI/xaY4sl7F
# S/F6HdISYpyeBlKjcsHVy5Cj7azh8UXVZYa4k+AeEseIB21/MQpynet1S1EuifGH
# Ms0Zh8axQAbJ+rDlupWsRiO63WTAPt5OsL/uEH20xZ/50m8sidF9tIZ1QrsLq8JF
# i99Zm+OncY3ysG2mQAgcsz3x7254Q2mHOSuDWKDDXx6VCZ7ihmAEtnUbL1rCngdf
# 4evV71tVyhf+4KTebjk03t6mpqYvjO3W7yuObH8NOVaAcYgOjUi0G9AN/vYwBZHf
# BAhikGO8pKxW6U/Krc2oQWaKpmGzKK1OpSVi5VZuB6has6Mm3wIDAQABo4IBYDCC
# AVwwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUEB15NHKwwcMjbBDrbk8UA+4uHysw
# HwYDVR0jBBgwFoAUzolPglGqFaKEYsoxI2HSYfv4/ngwZwYIKwYBBQUHAQEEWzBZ
# MCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAyBggrBgEFBQcw
# AoYmaHR0cDovL2FpYS5lbnRydXN0Lm5ldC9ldmNzMi1jaGFpbi5wN2MwMQYDVR0f
# BCowKDAmoCSgIoYgaHR0cDovL2NybC5lbnRydXN0Lm5ldC9ldmNzMi5jcmwwDgYD
# VR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMEsGA1UdIAREMEIwNwYK
# YIZIAYb6bAoBAjApMCcGCCsGAQUFBwIBFhtodHRwczovL3d3dy5lbnRydXN0Lm5l
# dC9ycGEwBwYFZ4EMAQMwDQYJKoZIhvcNAQELBQADggIBAIXuiHbQsWUCEhlA76KA
# YJCAbtiCXDerGtT1z27L+7/TcVUBOv2luPJ9C9qXVuQIwa0CTYNQ/kDKSkhWCJxi
# vk4OPaGi5yONchUlHsLQFXQOLDvSFbIYjeUvLAvOp30NgLyy7/Sw3SQsiSKmuLrK
# fSbNTqj0Lf48W+TQk5YD0TzDSSQG8+J4oVfYyyFxoo4C9kAoh7gTjwtj01p5QLKe
# LYJG5lpH6EomLDftK9Pe0woz46smPdL+d9dfvA51O3jS/xHt4kBpqWcWOZ2C5ZGx
# ydU6Ru+U7NVlHATRzAM/dxGJGqFCeTs1CpQF9vykl8iiSpPjzJ+CdrJbQ8gA0kCa
# +G7CagqQ3bkSMvRQllexC5HW6CiUKc8rJfZsCGOpEqtrfuxbiUUZ2og8BOliaFHK
# ZENurT73LtMNygx+yMcbaJkpfEheDJuGK82avSh9HFkyuJD3MI2MafN2OtyXyO/M
# sseiqHwpcRdwDZr0mkOrN9y1YOo62BYRVDVUep9X5lQ/MEA9c6iMgrQ4/E8kk4Jo
# LC7pe21qAP1ICIbjS7g5t4cbPfeFBtvSZeMANKmlDXQkedoGOOnOxqCuhxc3a0LX
# B746Q/VF6hookZlTqDXuu6aeIdD3tpLt0Dx8D69FY2Si/eMdn6dKDsT7CXYFve0S
# 1DDwrqhTIXI9wPojPbu8ZXPzMYIFXTCCBVkCAQEwdzBjMQswCQYDVQQGEwJVUzEW
# MBQGA1UEChMNRW50cnVzdCwgSW5jLjE8MDoGA1UEAxMzRW50cnVzdCBFeHRlbmRl
# ZCBWYWxpZGF0aW9uIENvZGUgU2lnbmluZyBDQSAtIEVWQ1MyAhAWdy8OxRnHb5Id
# XyBiye3RMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKEC
# gAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwG
# CisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIOTA8V/QjeKT1PHtBLsbpr83ZmGX
# wCpJH3reZwJl5KPvMA0GCSqGSIb3DQEBAQUABIICAHG1YugMamlfdAoz2FlXVPqY
# CPtl9VcDjr1NB0tm5AeaHVWWy5oHBEcEakrwrfNhD9b3rZUSanl/YUzjmdv53s2M
# uShmkld4loCGOJCEeL1RTDvFZ9y+WrhEJeSVqbaFP/MF/Q/LOepuB9EbeNLr3OeX
# kEnHc1rhTG5yqO7mUPmW+8H4ux27NUW33VSnMyT8AwvJMBytuLR2vZzGlrg7ZauN
# fmgyCXHuooOgqb/HZo0/2lDX0zTGsvwUAwio+deXp05VNPZzs4aR8qxX4XbFWDkU
# epYKxa83TRlix8lxfVriC25Isf1D5eeeH5TF7QjlcVkRmospl3OzTX0k2ug1ms9E
# hjpeV6LcdoZK8IWBImaTyWGZVLyHqjKfZcuU6/vF1TYk9OoyHOcRZskXG0zv+dsx
# Vhf1/gA7Kc31PXhDSiE11M5bTX5/yNZRXWdX7jvJmk09v5yY43Mpe6OVN4wR30a/
# FT5VYZzBByvZzBB5jTdPjGuG5e30UN/lQz0Nw6qST3yIy0nIfOunpEj9MaMorw76
# vud0TE/kC9uDRT/QBViWSGIfXt1CcY0P2xE5dl5YwojrQgukImBlO/QO0SV1siJ5
# AQ5c5eIegfQ+ugrfGQHlHgfnTztYLDeHI25rMJNZlajJLE1+zMD8QAktStj2148L
# JP/DiJt2/B2ZPaYwZ1shoYICMDCCAiwGCSqGSIb3DQEJBjGCAh0wggIZAgEBMIGG
# MHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT
# EHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJl
# ZCBJRCBUaW1lc3RhbXBpbmcgQ0ECEA1CSuC+Ooj/YEAhzhQA8N0wDQYJYIZIAWUD
# BAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEP
# Fw0yMjA0MDEwMTI1NDhaMC8GCSqGSIb3DQEJBDEiBCCUxEdctS2N1FeAyHBzdj+P
# 7DoMEJyz/wqviMWGi+xwZDANBgkqhkiG9w0BAQEFAASCAQAV8xWcuo7Cw+NlKQhV
# HCS3Bu8I4+e3xkLlG58v9VEy79DBHsvizCI0JFLNv5Px/nCKkWwJPDmu9LA7kDVp
# /HPNbO5RgrPFbHiz5p/O+xcshl4sd1fD4djaX7f0+1kfSwNelXw5ALCoHeN+YrGd
# 8XzimWSgI39vKO0K857shNj7/DT2CGqKCe8eoT1AyBKg8voSBFi69YjOM+gql46h
# 0ibKh32W/rke8Q0Tp3A+OSdZbYdMqyPmza+IqsCJdJ4IQMBawsvacenGMGlPp5SV
# OKS7ULYX1x1nxo1amsVbHVyDD8MVKxovyrpfLJISfnTH4+ln7qHHtNZsztoPBgfc
# l5ai
# SIG # End signature block