Public/Update-ADFSTkInstitutionConfiguration.ps1

function Update-ADFSTkInstitutionConfiguration {
    [CmdletBinding(SupportsShouldProcess = $true)]
    param(
        $ConfigurationFile
    )

    #This is ther version we can upgrade to
    $currentConfigVersion = '1.3'

    #Get All paths
    if ([string]::IsNullOrEmpty($Global:ADFSTkPaths)) {
        $Global:ADFSTkPaths = Get-ADFSTKPaths
    }

    #Create main dirs
    ADFSTk-TestAndCreateDir -Path $Global:ADFSTkPaths.mainDir               -PathName "ADFSTk install directory" #C:\ADFSToolkit
    ADFSTk-TestAndCreateDir -Path $Global:ADFSTkPaths.mainConfigDir         -PathName "Main configuration" #C:\ADFSToolkit\config
    ADFSTk-TestAndCreateDir -Path $Global:ADFSTkPaths.mainBackupDir         -PathName "Main backup" #C:\ADFSToolkit\config\backup
    ADFSTk-TestAndCreateDir -Path $Global:ADFSTkPaths.cacheDir              -PathName "Cache directory" #C:\ADFSToolkit\cache
    ADFSTk-TestAndCreateDir -Path $Global:ADFSTkPaths.institutionDir        -PathName "Institution config directory" #C:\ADFSToolkit\config\institution
    ADFSTk-TestAndCreateDir -Path $Global:ADFSTkPaths.institutionBackupDir  -PathName "Institution backup directory" #C:\ADFSToolkit\config\institution\backup
    ADFSTk-TestAndCreateDir -Path $Global:ADFSTkPaths.federationDir         -PathName "Federation config directory" #C:\ADFSToolkit\config\federation

    try {
        $mainConfiguration = Get-ADFSTkConfiguration
    }
    catch {
        #inform that we need a main config and that we will call that now
        Write-ADFSTkHost confNeedMainConfigurationMessage -Style Info
        $mainConfiguration = New-ADFSTkConfiguration -Passthru
    }
    
    $defaultConfigFile = $Global:ADFSTkPaths.defaultConfigFile

    $federationName = $mainConfiguration.FederationConfig.Federation.FederationName
    
    if (![string]::IsNullOrEmpty($federationName)) {
        $defaultFederationConfigDir = Join-Path $Global:ADFSTkPaths.federationDir $federationName
        
        #Check if the federation dir exists and if not, create it
        ADFSTk-TestAndCreateDir -Path $defaultFederationConfigDir -PathName "$federationName config directory"

        $allDefaultFederationConfigFiles = Get-ChildItem -Path $defaultFederationConfigDir -Filter "*_defaultConfigFile.xml"
        if ([string]::IsNullOrEmpty($allDefaultFederationConfigFiles)) {
            Write-ADFSTkHost -WriteLine -AddSpaceAfter
            Write-ADFSTkHost confCopyFederationDefaultFolderMessage -Style Info -AddSpaceAfter -f $defaultFederationConfigDir
        
            Read-Host (Get-ADFSTkLanguageText cPressEnterKey) | Out-Null

            $allDefaultFederationConfigFiles = Get-ChildItem -Path $defaultFederationConfigDir -Filter "*_defaultConfigFile.xml"
        }
        
        if ($allDefaultFederationConfigFiles -eq $null) {
            $defaultFederationConfigFile = $null
        }
        elseif ($allDefaultFederationConfigFiles -is [System.IO.FileSystemInfo]) {
            $defaultFederationConfigFile = $allDefaultFederationConfigFiles.FullName
        }
        elseif ($allDefaultFederationConfigFiles -is [System.Array]) {
            $defaultFederationConfigFile = $allDefaultFederationConfigFiles | Out-GridView -Title (Get-ADFSTkLanguageText confSelectDefaultFedConfigFile) -OutputMode Single | Select -ExpandProperty Fullname
        }
        else {
            #We should never be here...
        }

        if ([string]::IsNullOrEmpty($defaultFederationConfigFile)) {
            if (!(Get-ADFSTkAnswer (Get-ADFSTkLanguageText confFederationDefaultConfigNotFoundQuestion -f $federationName) -DefaultYes)) {
                Write-ADFSTkLog (Get-ADFSTkLanguageText confFederationDefaultConfigNotFound) -MajorFault
            }
        }
        else {
            try {
                [xml]$defaultFederationConfig = Get-Content $defaultFederationConfigFile

                if ($defaultFederationConfig.configuration.ConfigVersion -ne $currentConfigVersion) {
                    Write-ADFSTkHost confNotAValidVersionWarning -Style Attention
                }
            }
            catch {
                Write-ADFSTkLog (Get-ADFSTkLanguageText confCouldNotOpenFederationDefaultConfig -f $defaultFederationConfig, $_) -MajorFault
            }
        }
    }

    #Try to open default config
    try {
        [xml]$defaultConfig = Get-Content $defaultConfigFile
    }
    catch {
        Write-ADFSTkLog (Get-ADFSTkLanguageText confCouldNotOpenDefaultConfig -f $defaultConfigFile, $_) -MajorFault
    }

    #region Copy Local Transform Rule File
    if (!(Test-path $Global:ADFSTkPaths.institutionLocalTransformRulesFile)) {
        Write-ADFSTkHost confLocalTransformRulesMessage -Style Info -AddLinesOverAndUnder -f $Global:ADFSTkPaths.institutionLocalTransformRulesFile
        Copy-item -Path $Global:ADFSTkPaths.defaultInstitutionLocalTransformRulesFile -Destination $Global:ADFSTkPaths.institutionLocalTransformRulesFile
    }
    #endregion

    #region Select Institution config(s)
    
    $selectedConfigs = @()

    if ($PSBoundParameters.ContainsKey('ConfigurationFile')) {
        if (!(Test-Path $ConfigurationFile)) {
            Write-ADFSTkLog (Get-ADFSTkLanguageText cFileDontExist -f $ConfigurationFile) -MajorFault
        }

        $ConfigurationFilePath = Get-ChildItem $ConfigurationFile

        #Check if it's an old file that neds to be copied to the institution dir
        if ($ConfigurationFilePath.Directory.FullName -ne $Global:ADFSTkPaths.institutionDir) {
            #Copy the configuration file to new location
            $newFileName = Join-Path $Global:ADFSTkPaths.institutionDir $ConfigurationFilePath.Name
            if (Test-Path $newFileName) {
                Write-ADFSTkLog (Get-ADFSTkLanguageText confInstConfFileAlreadyUpgraded -f (Join-Path $ConfigurationFilePath.Directory $ConfigurationFilePath.name), $newFileName) -MajorFault
            }
            else {
                Copy-Item $ConfigurationFilePath.FullName $newFileName
            }
        }

        #Copy the ManualSP file to new location
        [xml]$selectedConfigSettings = Get-Content $ConfigurationFile
        $selectedConfigManualSP = $selectedConfigSettings.configuration.LocalRelyingPartyFile
        
        $oldManualSPFile = Join-Path $ConfigurationFilePath.Directory.FullName $selectedConfigManualSP
        $newManualSPFile = Join-Path $Global:ADFSTkPaths.institutionDir $selectedConfigManualSP

        if (Test-Path $oldManualSPFile) {
            if (Test-Path $newManualSPFile) {
                Write-ADFSTkLog (Get-ADFSTkLanguageText confManualSPFileAlreadyExists -f $oldManualSPFile, $Global:ADFSTkPaths.institutionDir) -EntryType Warning
            }
            else {
                Copy-Item $oldManualSPFile $newManualSPFile
                Write-ADFSTkLog (Get-ADFSTkLanguageText confManualSPFileCopied -f $oldManualSPFile, $Global:ADFSTkPaths.institutionDir) -EntryType Information
            }
        }
        else {
            Write-ADFSTkHost confLocalManualSettingsMessage -Style Info -AddLinesOverAndUnder
            Copy-item -Path $Global:ADFSTkPaths.defaultInstitutionLocalSPFile -Destination $newManualSPFile
        }

        $selectedConfigs += Add-ADFSTkConfigurationItem -ConfigurationItem $newFileName -PassThru 
    }
    else {
        $allCurrentConfigs = Get-ADFSTkConfiguration -ConfigFilesOnly

        if ([string]::IsNullOrEmpty($allCurrentConfigs)) {
            $currentConfigs = @()
            $currentConfigs += Get-ChildItem $Global:ADFSTkPaths.mainDir -Filter '*.xml' `
                -Recurse | ? { $_.Directory.Name -notcontains 'cache' -and `
                    $_.Directory.Name -notcontains 'federation' -and `
                    $_.Name -ne 'config.ADFSTk.xml' -and -not`
                    $_.Name.EndsWith('_defaultConfigFile.xml') -and `
                    $_.Directory.Name -notcontains 'backup' } | `
                Select Directory, Name, LastWriteTime | `
                Sort Directory, Name
            
            if ($currentConfigs.Count -eq 0) {
                Write-ADFSTkLog (Get-ADFSTkLanguageText confNoInstConfFiles) -MajorFault
            }

            #Add all selected federation config files to ADFSTk configuration
            $selectedConfigsTemp = $currentConfigs | Out-GridView -Title (Get-ADFSTkLanguageText confSelectInstConfFileToHandle) -PassThru

            foreach ($selectedConfig in $selectedConfigsTemp) {
                #Check if it's an old file that neds to be copied to the institution dir
                if ($selectedConfig.Directory -ne $Global:ADFSTkPaths.institutionDir) {
                    #Copy the configuration file to new location
                    $newFileName = Join-Path $Global:ADFSTkPaths.institutionDir $selectedConfig.Name
                    if (Test-Path $newFileName) {
                        Write-ADFSTkLog (Get-ADFSTkLanguageText confInstConfFileAlreadyUpgraded -f (Join-Path $selectedConfig.Directory $selectedConfig.name), $newFileName) -MajorFault
                    }
                    else {
                        Copy-Item (Join-Path $selectedConfig.Directory $selectedConfig.name) $newFileName
                    }

                    #Copy the ManualSP file to new location
                    [xml]$selectedConfigSettings = Get-Content (Join-Path $selectedConfig.Directory $selectedConfig.name)
                    $selectedConfigManualSP = $selectedConfigSettings.configuration.LocalRelyingPartyFile
                    
                    $oldManualSPFile = Join-Path $selectedConfig.Directory $selectedConfigManualSP
                    $newManualSPFile = Join-Path $Global:ADFSTkPaths.institutionDir $selectedConfigManualSP

                    if (Test-Path $oldManualSPFile) {
                        if (Test-Path $newManualSPFile) {
                            Write-ADFSTkLog (Get-ADFSTkLanguageText confManualSPFileAlreadyExists -f $oldManualSPFile, $Global:ADFSTkPaths.institutionDir) -EntryType Warning
                        }
                        else {
                            Copy-Item $oldManualSPFile $newManualSPFile
                            Write-ADFSTkLog (Get-ADFSTkLanguageText confManualSPFileCopied -f $oldManualSPFile, $Global:ADFSTkPaths.institutionDir) -EntryType Information
                        }
                    }
                    $selectedConfig.Directory = $Global:ADFSTkPaths.institutionDir
                }

                $selectedConfigs += Add-ADFSTkConfigurationItem -ConfigurationItem (Join-Path $selectedConfig.Directory $selectedConfig.Name) -PassThru
            }
        }
        else {
            $selectedConfigs += $allCurrentConfigs | Out-GridView -Title (Get-ADFSTkLanguageText confSelectInstConfFileToHandle) -PassThru
        }
    }

    if ($selectedConfigs.Count -eq 0) {
        Write-ADFSTkLog (Get-ADFSTkLanguageText confNoInstConfigFileSelectedborting) -MajorFault
    }

    #endregion

    #region Handle each institution config file
    foreach ($configFile in $selectedConfigs) {
        Write-ADFSTkHost confProcessingInstConfig -f $configFile.configFile -AddLinesOverAndUnder -Style Info
        
        $continue = $true
        try {
            [xml]$config = Get-Content $configFile.ConfigFile
        }
        catch {
            Write-ADFSTkLog (Get-ADFSTkLanguageText confCouldNotOpenInstConfigFile -f $_) -EntryType Error
            $continue = $false
        }

        if ($continue) {
            #Load the eventlog
            if ([string]::IsNullOrEmpty((Write-ADFSTkLog -GetEventLogName))) {
                $Settings = $config
                if (Verify-ADFSTkEventLogUsage) {
                    #If we evaluated as true, the eventlog is now set up and we link the WriteADFSTklog to it
                    Write-ADFSTkLog -SetEventLogName $config.configuration.logging.LogName -SetEventLogSource $config.configuration.logging.Source

                }
            }

            if ([string]::IsNullOrEmpty($config.configuration.ConfigVersion)) {
                Write-ADFSTkLog (Get-ADFSTkLanguageText confCouldNotRetrieveVersion) -EntryType Error
            }
            elseif ($config.configuration.ConfigVersion -eq $currentConfigVersion) {
                Write-ADFSTkLog (Get-ADFSTkLanguageText confInstConfAlreadyCorrectVersion -f $currentConfigVersion) -EntryType Information
            }
            else {
                $oldConfigVersion = $config.configuration.ConfigVersion
                $configFileObject = Get-ChildItem $configFile.configFile

                #Check if the config is enabled and disable it if so
                if ($configFile.Enabled) {
                    Write-ADFSTkHost confInstitutionConfigEnabledWarning -Style Attention
                    Set-ADFSTkInstitutionConfiguration -ConfigurationItem $configFile.configFile -Status Disabled
                }

                #First take a backup of the current file
                if (!(Test-Path $Global:ADFSTkPaths.institutionBackupDir)) {
                    Write-ADFSTkVerboseLog -Message (Get-ADFSTkLanguageText cFileDontExist -f $Global:ADFSTkPaths.institutionBackupDir)

                    New-Item -ItemType Directory -Path $Global:ADFSTkPaths.institutionBackupDir | Out-Null
                
                    Write-ADFSTkVerboseLog -Message (Get-ADFSTkLanguageText cCreated)
                }
                
                $backupFilename = "{0}_backup_v{3}_{1}{2}" -f $configFileObject.BaseName, (Get-Date).tostring("yyyyMMdd_HHmmss"), $configFile.Extension, $config.configuration.ConfigVersion
                $backupFile = Join-Path $Global:ADFSTkPaths.institutionBackupDir $backupFilename
                Copy-Item -Path $configFile.configFile -Destination $backupFile | Out-Null

                Write-ADFSTkLog (Get-ADFSTkLanguageText confOldConfBackedUpTo -f $backupFile) -ForegroundColor Green

                ###Now lets upgrade in steps!###
                
                $RemoveCache = $false

                #v0.9 --> v1.0
                $currentVersion = '0.9'
                $newVersion = '1.0'
                if ($config.configuration.ConfigVersion -eq $currentVersion) {
                    Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText confUpdatingInstConfigFromTo -f $currentVersion, $newVersion)
                    
                    if ($config.configuration.LocalRelyingPartyFile -eq $null) {
                        Add-ADFSTkXML -XPathParentNode "configuration" -NodeName "LocalRelyingPartyFile" -RefNodeName "MetadataCacheFile"
                    }
                   
                    Update-ADFSTkXML -XPath "configuration/LocalRelyingPartyFile" -ExampleValue 'get-ADFSTkLocalManualSPSettings.ps1'

                    $config.configuration.ConfigVersion = $newVersion
                    $config.Save($configFile.configFile);
                 
                }
                #v1.0 --> v1.1
                $currentVersion = '1.0'
                $newVersion = '1.1'
                if ($config.configuration.ConfigVersion -eq $currentVersion) {
                    Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText confUpdatingInstConfigFromTo -f $currentVersion, $newVersion)
                    
                    if ($config.configuration.eduPersonPrincipalNameRessignable -eq $null) {
                        Add-ADFSTkXML -XPathParentNode "configuration" -NodeName "eduPersonPrincipalNameRessignable" -RefNodeName "MetadataPrefixSeparator"
                    }
                   
                    Update-ADFSTkXML -XPath "configuration/eduPersonPrincipalNameRessignable" -ExampleValue 'true/false'

                    $config.configuration.ConfigVersion = $newVersion
                    $config.Save($configFile.configFile);

                    if ($RemoveCache -eq $false) {
                        $RemoveCache = $true
                        Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText confCacheNeedsToBeRemoved)
                    }
                }

                #v1.1 --> v1.2
                $currentVersion = '1.1'
                $newVersion = '1.2'
                if ($config.configuration.ConfigVersion -eq $currentVersion) {
                    Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText confUpdatingInstConfigFromTo -f $currentVersion, $newVersion)
                    
                    Remove-ADFSTkXML -XPath 'configuration/WorkingPath'
                    Remove-ADFSTkXML -XPath 'configuration/ConfigDir'
                    Remove-ADFSTkXML -XPath 'configuration/CacheDir'

                    foreach ($store in $config.configuration.storeConfig.stores.store) {
                        if ([string]::IsNullOrEmpty($store.storetype)) {
                            $store.SetAttribute('storetype', $store.name)

                            'issuer', 'type', 'order' | % {
                                $attributeValue = $store.$_
                                if (![string]::IsNullOrEmpty($attributeValue)) {
                                    $store.RemoveAttribute($_)
                                    $store.SetAttribute($_, $attributeValue)
                                }
                            }
                        }
                    }

                    $config.configuration.ConfigVersion = $newVersion
                    $config.Save($configFile.configFile);
                }

                #v1.2 --> v1.3
                $currentVersion = '1.2'
                $newVersion = '1.3'
                if ($config.configuration.ConfigVersion -eq $currentVersion) {
                    Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText confUpdatingInstConfigFromTo -f $currentVersion, $newVersion)

                    if (![string]::IsNullOrEmpty($config.configuration.storeConfig.transformRules)) {
                        Write-ADFSTkLog (Get-ADFSTkLanguageText confMoveNodeFromStoreConfigToConfig -f 'transformRules')
                        $config.configuration.AppendChild($config.configuration.storeConfig.transformRules) | Out-Null
                    }

                    if (![string]::IsNullOrEmpty($config.configuration.storeConfig.attributes)) {
                        Write-ADFSTkLog (Get-ADFSTkLanguageText confMoveNodeFromStoreConfigToConfig -f 'attributes')
                        $config.configuration.AppendChild($config.configuration.storeConfig.attributes) | Out-Null
                    }

                    $commonName = $config.configuration.attributes.attribute | ? type -eq "http://schemas.xmlsoap.org/claims/CommonName"
                    if ($commonName.store -eq "Active Directory" -and $commonName.name -eq "cn")
                    {
                        Write-ADFSTkHost confChangeCommonNameToDisplayName
                        if (Get-ADFSTkAnswer (Get-ADFSTkLanguageText confDoYouWantToChangeCommonName) -DefaultYes)
                        {
                            $commonName.name = "displayname"
                            Write-ADFSTkLog (Get-ADFSTkLanguageText confCommonNameChangedFromCnToDisplayName)
                        }
                    }

                    $config.configuration.ConfigVersion = $newVersion
                    $config.Save($configFile.configFile);
                }

                Write-ADFSTkLog (Get-ADFSTkLanguageText confUpdatedInstConfigDone -f $configFile.configFile, $oldConfigVersion, $currentConfigVersion) -EntryType Information
            }

            #Add any new attributes from Default Config or Default Federation Config to the Institution Config
            if ([string]::IsNullOrEmpty($defaultFederationConfig)) {
                #Compare Default Config
                $compare = Compare-ADFSTkObject $defaultConfig.configuration.attributes.attribute.Type $config.configuration.attributes.attribute.Type -CompareType InFirstSetOnly
                if (![string]::IsNullOrEmpty($compare.CompareSet)) {
                    foreach ($type in $compare.CompareSet) {
                        $xmlNode = $defaultConfig.configuration.attributes.attribute | ? type -eq $type
                        Add-ADFSTkXMLNode -XPathParentNode 'configuration/attributes' -Node $xmlNode
                    }
                    $config.Save($configFile.configFile);
                    Write-ADFSTkLog (Get-ADFSTkLanguageText confAddedAttributeToInstitutionConfig -f ($compare.CompareSet -join [System.Environment]::NewLine)) -EventID 45 -EntryType Information
                }
            }
            else {
                #Compare Default Federation
                $compare = Compare-ADFSTkObject $defaultFederationConfig.configuration.attributes.attribute.Type $config.configuration.attributes.attribute.Type -CompareType InFirstSetOnly
                if (![string]::IsNullOrEmpty($compare.CompareSet)) {
                    foreach ($type in $compare.CompareSet) {
                        $xmlNode = $defaultFederationConfig.configuration.attributes.attribute | ? type -eq $type
                        Add-ADFSTkXMLNode -XPathParentNode 'configuration/attributes' -Node $xmlNode
                    }
                    $config.Save($configFile.configFile);
                    Write-ADFSTkLog (Get-ADFSTkLanguageText confAddedAttributeToInstitutionConfig -f ($compare.CompareSet -join [System.Environment]::NewLine)) -EventID 45 -EntryType Information
                }
            }
        }
    }

    Write-ADFSTkLog (Get-ADFSTkLanguageText confUpdatedInstConfigAllDone) -EntryType Information
    if ($RemoveCache) {
        Write-ADFSTkHost confDeleteCacheWarning -Style Attention
        if (Get-ADFSTkAnswer (Get-ADFSTkLanguageText confDeleteCacheQuestion) -DefaultYes) {
            Get-ChildItem $Global:ADFSTkPaths.cacheDir | Remove-Item -Confirm:$false
        }
    }
    #endregion
}
#endregion


function Add-ADFSTkXML {
    param (
        $NodeName,
        $XPathParentNode,
        $RefNodeName,
        $Value = [string]::Empty
    )

    $configurationNode = Select-Xml -Xml $config -XPath $XPathParentNode
    $configurationNodeChild = $config.CreateNode("element", $NodeName, $null)
    $configurationNodeChild.InnerText = $Value

    #$configurationNode.Node.AppendChild($configurationNodeChild) | Out-Null
    $refNode = Select-Xml -Xml $config -XPath "$XPathParentNode/$RefNodeName"
    if ($refNode -is [Object[]]) {
        $refNode = $refNode[-1]
    }
    $configurationNode.Node.InsertAfter($configurationNodeChild, $refNode.Node) | Out-Null
}

function Add-ADFSTkXMLNode {
    param (
        $XPathParentNode,
        $Node
    )
    
    $configurationNode = Select-Xml -Xml $config -XPath $XPathParentNode
    $configurationNode.Node.AppendChild($config.ImportNode($Node, $true)) | Out-Null
}

function Update-ADFSTkXML {
    param (
        $XPath,
        $ExampleValue
    )

    $params = @{
        XPath        = $XPath
        ExampleValue = $ExampleValue 
        NewConfig    = $config
    }
    
    $defaultFederationConfigNode = $null

    if (![string]::IsNullOrEmpty($defaultFederationConfig)) {
        $defaultFederationConfigNode = Select-Xml -Xml $defaultFederationConfig -XPath $XPath
    }

    if ([string]::IsNullOrEmpty($defaultFederationConfigNode)) {
        $params.DefaultConfig = $defaultConfig
    }
    else {
        $params.DefaultConfig = $defaultFederationConfig
    }

    Set-ADFSTkConfigItem @params
}

function Remove-ADFSTkXML {
    param (
        $XPath
    )

    $node = $config.SelectSingleNode($XPath)
    if (![string]::IsNullOrEmpty($node)) {
        $node.ParentNode.RemoveChild($node) | Out-Null
    }
}
# SIG # Begin signature block
# MIIRbgYJKoZIhvcNAQcCoIIRXzCCEVsCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUz4juDCJqKsMsKbBoB29pARO1
# H+eggg51MIIEfTCCA2WgAwIBAgIDG+cVMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV
# BAYTAlVTMSEwHwYDVQQKExhUaGUgR28gRGFkZHkgR3JvdXAsIEluYy4xMTAvBgNV
# BAsTKEdvIERhZGR5IENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN
# MTQwMTAxMDcwMDAwWhcNMzEwNTMwMDcwMDAwWjCBgzELMAkGA1UEBhMCVVMxEDAO
# BgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdv
# RGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmlj
# YXRlIEF1dGhvcml0eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
# AQEAv3FiCPH6WTT3G8kYo/eASVjpIoMTpsUgQwE7hPHmhUmfJ+r2hBtOoLTbcJjH
# MgGxBT4HTu70+k8vWTAi56sZVmvigAf88xZ1gDlRe+X5NbZ0TqmNghPktj+pA4P6
# or6KFWp/3gvDthkUBcrqw6gElDtGfDIN8wBmIsiNaW02jBEYt9OyHGC0OPoCjM7T
# 3UYH3go+6118yHz7sCtTpJJiaVElBWEaRIGMLKlDliPfrDqBmg4pxRyp6V0etp6e
# MAo5zvGIgPtLXcwy7IViQyU0AlYnAZG0O3AqP26x6JyIAX2f1PnbU21gnb8s51ir
# uF9G/M7EGwM8CetJMVxpRrPgRwIDAQABo4IBFzCCARMwDwYDVR0TAQH/BAUwAwEB
# /zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9BUFuIMGU2g/e
# MB8GA1UdIwQYMBaAFNLEsNKR1EwRcbNhyz2h/t2oatTjMDQGCCsGAQUFBwEBBCgw
# JjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRkeS5jb20vMDIGA1UdHwQr
# MCkwJ6AloCOGIWh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Ryb290LmNybDBGBgNV
# HSAEPzA9MDsGBFUdIAAwMzAxBggrBgEFBQcCARYlaHR0cHM6Ly9jZXJ0cy5nb2Rh
# ZGR5LmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAWQtTvZKGEack
# e+1bMc8dH2xwxbhuvk679r6XUOEwf7ooXGKUwuN+M/f7QnaF25UcjCJYdQkMiGVn
# OQoWCcWgOJekxSOTP7QYpgEGRJHjp2kntFolfzq3Ms3dhP8qOCkzpN1nsoX+oYgg
# HFCJyNwq9kIDN0zmiN/VryTyscPfzLXs4Jlet0lUIDyUGAzHHFIYSaRt4bNYC8nY
# 7NmuHDKOKHAN4v6mF56ED71XcLNa6R+ghlO773z/aQvgSMO3kwvIClTErF0UZzds
# yqUvMQg3qm5vjLyb4lddJIGvl5echK1srDdMZvNhkREg5L4wn3qkKQmw4TRfZHcY
# QFHfjDCmrzCCBNAwggO4oAMCAQICAQcwDQYJKoZIhvcNAQELBQAwgYMxCzAJBgNV
# BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRow
# GAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UEAxMoR28gRGFkZHkgUm9v
# dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjAeFw0xMTA1MDMwNzAwMDBaFw0z
# MTA1MDMwNzAwMDBaMIG0MQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTET
# MBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5jb20sIEluYy4x
# LTArBgNVBAsTJGh0dHA6Ly9jZXJ0cy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzEz
# MDEGA1UEAxMqR28gRGFkZHkgU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eSAt
# IEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAueDLENSvdr3Uk2Lr
# MGS4gQhswwTZYheOL/8+Zc+PzmLmPFIc2hZFS1WreGtjg2KQzg9pbJnIGhSLTMxF
# M+qI3J6jryv+gGGdeVfEzy70PzA8XUf8mha8wzeWQVGOEUtU+Ci+0Iy+8DA4HvOw
# JvhmR2Nt3nEmR484R1PRRh2049wA6kWsvbxx2apvANvbzTA6eU9fTEf4He9bwsSd
# YDuxskOR2KQzTuqz1idPrSWKpcb01dCmrnQFZFeItURV1C0qOj74uL3pMgoClGTE
# FjpQ8Uqu53kzrwwgB3/o3wQ5wmkCbGNS+nfBG8h0h8i5kxhQVDVLaU68O9NJLh/c
# wdJS+wIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
# AQYwHQYDVR0OBBYEFEDCvSeOzDSDMKIz1/tss/C0LIDOMB8GA1UdIwQYMBaAFDqa
# hQcQZyi27/a9BUFuIMGU2g/eMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZ29kYWRkeS5jb20vMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6
# Ly9jcmwuZ29kYWRkeS5jb20vZ2Ryb290LWcyLmNybDBGBgNVHSAEPzA9MDsGBFUd
# IAAwMzAxBggrBgEFBQcCARYlaHR0cHM6Ly9jZXJ0cy5nb2RhZGR5LmNvbS9yZXBv
# c2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEACH5skxDIOLiWqZBL/6FfTwTvbD6c
# iAbJUI+mc/dXMRu+vOQv2/i601vgtOfmeWIODKLXamNzMbX1qEikOwgtol2Q17R8
# JU8RVjDEtkSdeyyd5V7m7wxhqr/kKhvuhJ64g33BQ85EpxNwDZEf9MgTrYNg2dhy
# qHMkHrWsIg7KF4liWEQbq4klAQAPzcQbYttRtNMPUSqb9Lxz/HbONqTN2dgs6q6b
# 9SqykNFNdRiKP4pBkCN9W0v+pANYm0ayw2Bgg/h9UEHOwqGQw7vvAi/SFVTuRBXZ
# Cq6nijPtsS12NibcBOuf92EfFdyHb+5GliitoSZ9CgmnLgSjjbz4vAQwATCCBRww
# ggQEoAMCAQICCDeMqUwECkf0MA0GCSqGSIb3DQEBCwUAMIG0MQswCQYDVQQGEwJV
# UzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UE
# ChMRR29EYWRkeS5jb20sIEluYy4xLTArBgNVBAsTJGh0dHA6Ly9jZXJ0cy5nb2Rh
# ZGR5LmNvbS9yZXBvc2l0b3J5LzEzMDEGA1UEAxMqR28gRGFkZHkgU2VjdXJlIENl
# cnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTIwMDEwODExMjIyNFoXDTIxMDMw
# ODE4NTgwMFowXjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xDzANBgNV
# BAcTBk90dGF3YTEVMBMGA1UEChMMQ0FOQVJJRSBJbmMuMRUwEwYDVQQDEwxDQU5B
# UklFIEluYy4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZhfCjFqiT
# mN1uLoySixnwaOjf/ZAL9P6SvjlCaBA2mutoorEgnzUP8HnOIcvMRgEMPmpaZ8eg
# M93Bmx9d41xoarsQpCN3DhYOo+b3fWnPucVtpxbul2OFePv63mw/uvr+dqkv4b/f
# 3Tg+ilQbpsNonbvh9MKEFv8Pn9koj0ySV+qxz34PxTVAe6g//pel3/3i9fqilCnI
# Ecx4zg/+NKBeOWROSs4oXo3IvBjVrunmz+YuieSr78TqIE6hD8JF2q1wKwfMB3+x
# 7dEXZAus9WtIU/qITATtEfO9QAgrrYL4F1MLN+osSp8my5eCOjnLTQc47q574V3z
# QhsIHW7yBXLdAgMBAAGjggGFMIIBgTAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG
# CCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDA1BgNVHR8ELjAsMCqgKKAmhiRodHRw
# Oi8vY3JsLmdvZGFkZHkuY29tL2dkaWcyczUtNS5jcmwwXQYDVR0gBFYwVDBIBgtg
# hkgBhv1tAQcXAjA5MDcGCCsGAQUFBwIBFitodHRwOi8vY2VydGlmaWNhdGVzLmdv
# ZGFkZHkuY29tL3JlcG9zaXRvcnkvMAgGBmeBDAEEATB2BggrBgEFBQcBAQRqMGgw
# JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmdvZGFkZHkuY29tLzBABggrBgEFBQcw
# AoY0aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5L2dk
# aWcyLmNydDAfBgNVHSMEGDAWgBRAwr0njsw0gzCiM9f7bLPwtCyAzjAdBgNVHQ4E
# FgQUUPnMg2nmYS8l7rmax3weVkrgz5AwDQYJKoZIhvcNAQELBQADggEBAIYabiAR
# aY4KhO6oWgNHPOBjoHuqUH7NwRGN/ztYJznRBZbdD50smoK5GR0FvUZ8TXhYoZOa
# zXe4NlFM4e6YcudU+EA/OF+sZHFBWziz1VS6U3sS+cGyJcxvelSoid0q3W3i9/Zy
# 6Nv2kk/DEJp49O47mPNovpL15yykX3Vo26GwC9peo4s/cKMzthmgrcF2uLkT+LW4
# 4xKhaL7nBTGDMhjno+a3t00SWCId7wzgQadIJ1QlFOKm0xgmuiW3LIqCG0apvaOf
# vWKTPKq68q+FbDPOO48oKrvw1c9K/m8gcnBLz6PX1REVIs5u3pvdOYBCz6uXyKxn
# t+Q5jDEK0NskLu0xggJjMIICXwIBATCBwTCBtDELMAkGA1UEBhMCVVMxEDAOBgNV
# BAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFk
# ZHkuY29tLCBJbmMuMS0wKwYDVQQLEyRodHRwOi8vY2VydHMuZ29kYWRkeS5jb20v
# cmVwb3NpdG9yeS8xMzAxBgNVBAMTKkdvIERhZGR5IFNlY3VyZSBDZXJ0aWZpY2F0
# ZSBBdXRob3JpdHkgLSBHMgIIN4ypTAQKR/QwCQYFKw4DAhoFAKB4MBgGCisGAQQB
# gjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYK
# KwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFNdhYgMU
# VZXx4Ke1Pfbcsy5X7Xj+MA0GCSqGSIb3DQEBAQUABIIBAMzMGoQ/b9YR5IJ3akRm
# Pj8PNAqBC/106Nbgwad05aR/IJGYsVEN6exju8XyuLu4NlL+FBbsBdUz5E9Uqqs7
# t7ef6NGhrN+FmPY8ByK7GsSc6ywtroBqJVCxS1gXSvgGkjPlDf1ktSrxPmn3AiC+
# nCiic3rMflD72vyG24L6hLFfFSoAXN7fW/H+SD9YikqgmPnOnx/fGQLkerG5RlzV
# wdiVv97anS4CP/Laop8K9w8fd7VUYR4NuxL6/cLzTErjde0GZSsl14zEgz9eDAKE
# orDC6OLRkyUlKUy2pCU5xbFl0/sZGTVCjqOHwCMSEldzSrS3VV3moTOOhU1XAzlK
# lfU=
# SIG # End signature block