Modules/Connection/Connection.psm1

function Connect-Tenant {
    <#
   .Description
   This function uses the various PowerShell modules to establish
   a connection to an M365 Tenant associated with provided
   credentials
   .Functionality
   Internal
   #>

   [CmdletBinding(DefaultParameterSetName='Manual')]
   param (
   [Parameter(ParameterSetName = 'Auto')]
   [Parameter(ParameterSetName = 'Manual')]
   [Parameter(Mandatory = $true)]
   [ValidateNotNullOrEmpty()]
   [ValidateSet("teams", "exo", "defender", "aad", "powerplatform", "sharepoint", IgnoreCase = $false)]
   [string[]]
   $ProductNames,

   [Parameter(ParameterSetName = 'Auto')]
   [Parameter(ParameterSetName = 'Manual')]
   [Parameter(Mandatory = $true)]
   [ValidateNotNullOrEmpty()]
   [ValidateSet("commercial", "gcc", "gcchigh", "dod", IgnoreCase = $false)]
   [string]
   $M365Environment,

   [Parameter(ParameterSetName = 'Auto')]
   [Parameter(Mandatory = $false)]
   [AllowNull()]
   [hashtable]
   $ServicePrincipalParams
   )
   Import-Module (Join-Path -Path $PSScriptRoot -ChildPath "ConnectHelpers.psm1")

   # Prevent duplicate sign ins
   $EXOAuthRequired = $true
   $SPOAuthRequired = $true
   $AADAuthRequired = $true

   $ProdAuthFailed = @()

   $N = 0
   $Len = $ProductNames.Length

   foreach ($Product in $ProductNames) {
       $N += 1
       $Percent = $N*100/$Len
       $ProgressParams = @{
           'Activity' = "Authenticating to each Product";
           'Status' = "Authenticating to $($Product); $($N) of $($Len) Products authenticated to.";
           'PercentComplete' = $Percent;
       }
       Write-Progress @ProgressParams
       try {
           switch ($Product) {
               "aad" {
                   $GraphScopes = Get-ScubaGearEntraMinimumPermissions

                   $GraphParams = @{
                       'M365Environment' = $M365Environment;
                       'Scopes' = $GraphScopes;
                   }
                   if($ServicePrincipalParams) {
                    $GraphParams += @{ServicePrincipalParams = $ServicePrincipalParams}
                   }
                   Connect-GraphHelper @GraphParams
                   $AADAuthRequired = $false
               }
               {($_ -eq "exo") -or ($_ -eq "defender")} {
                   if ($EXOAuthRequired) {
                       $EXOHelperParams = @{
                           M365Environment = $M365Environment;
                       }
                       if ($ServicePrincipalParams) {
                           $EXOHelperParams += @{ServicePrincipalParams = $ServicePrincipalParams}
                       }
                       Write-Verbose "Defender will require a sign in every single run regardless of what the LogIn parameter is set"
                       Connect-EXOHelper @EXOHelperParams
                       $EXOAuthRequired = $false
                   }
               }
               "powerplatform" {
                   $AddPowerAppsParams = @{
                       'ErrorAction' = 'Stop';
                   }
                   if ($ServicePrincipalParams.CertThumbprintParams) {
                       $AddPowerAppsParams += @{
                           CertificateThumbprint = $ServicePrincipalParams.CertThumbprintParams.CertificateThumbprint;
                           ApplicationId = $ServicePrincipalParams.CertThumbprintParams.AppID;
                           TenantID  = $ServicePrincipalParams.CertThumbprintParams.Organization; # Organization also works here
                       }
                   }
                   switch ($M365Environment) {
                       "commercial" {
                           $AddPowerAppsParams += @{'Endpoint'='prod';}
                       }
                       "gcc" {
                           $AddPowerAppsParams += @{'Endpoint'='usgov';}
                       }
                       "gcchigh" {
                           $AddPowerAppsParams += @{'Endpoint'='usgovhigh';}
                       }
                       "dod" {
                           $AddPowerAppsParams += @{'Endpoint'='dod';}
                       }
                   }
                   Add-PowerAppsAccount @AddPowerAppsParams | Out-Null
               }
               "sharepoint" {
                   if ($AADAuthRequired) {
                       $LimitedGraphParams = @{
                           'M365Environment' = $M365Environment;
                           'ErrorAction' = 'Stop';
                       }
                       if ($ServicePrincipalParams) {
                           $LimitedGraphParams += @{ServicePrincipalParams = $ServicePrincipalParams }
                       }
                       Connect-GraphHelper @LimitedGraphParams
                       $AADAuthRequired = $false
                   }
                   if ($SPOAuthRequired) {
                       $InitialDomain = (Get-MgBetaOrganization).VerifiedDomains | Where-Object {$_.isInitial}
                       $InitialDomainPrefix = $InitialDomain.Name.split(".")[0]
                       $SPOParams = @{
                           'ErrorAction' = 'Stop';
                       }
                       $PnPParams = @{
                           'ErrorAction' = 'Stop';
                       }

                       #pull api endpoint from json
                       $Url = Get-ScubaGearPermissions -Product "sharepoint" -Environment $M365Environment -Domain $InitialDomainPrefix -OutAs endpoint
                       $SPOParams += @{
                            'Url'= $Url;
                       }
                       $PnPParams += @{
                            'Url'= $Url;
                       }

                       #populate the rest of the parameters for splatting
                       switch ($M365Environment) {
                            "gcchigh" {
                                 $SPOParams += @{'Region' = "ITAR"; }
                                 $PnPParams += @{'AzureEnvironment' = 'USGovernmentHigh';}
                            }
                            "dod" {
                                 $SPOParams += @{'Region' = "ITAR"; }
                                 $PnPParams += @{'AzureEnvironment' = 'USGovernmentDoD';}
                            }

                       }
                       if ($ServicePrincipalParams.CertThumbprintParams) {
                           $PnPParams += @{
                               Thumbprint = $ServicePrincipalParams.CertThumbprintParams.CertificateThumbprint;
                               ClientId = $ServicePrincipalParams.CertThumbprintParams.AppID;
                               Tenant  = $ServicePrincipalParams.CertThumbprintParams.Organization; # Organization Domain is actually required here.
                           }
                           $env:PNPPOWERSHELL_UPDATECHECK = "false"  # disable PnP update banner
                           Connect-PnPOnline @PnPParams | Out-Null
                       }
                       else {
                           Connect-SPOService @SPOParams | Out-Null
                       }
                       $SPOAuthRequired = $false
                   }
               }
               "teams" {
                   $TeamsParams = @{'ErrorAction'= 'Stop'}
                   if ($ServicePrincipalParams.CertThumbprintParams) {
                       $TeamsConnectToTenant = @{
                           CertificateThumbprint = $ServicePrincipalParams.CertThumbprintParams.CertificateThumbprint;
                           ApplicationId = $ServicePrincipalParams.CertThumbprintParams.AppID;
                           TenantId  = $ServicePrincipalParams.CertThumbprintParams.Organization; # Organization Domain is actually required here.
                       }
                       $TeamsParams += $TeamsConnectToTenant
                   }
                   switch ($M365Environment) {
                       "gcchigh" {
                           $TeamsParams += @{'TeamsEnvironmentName'= 'TeamsGCCH';}
                       }
                       "dod" {
                           $TeamsParams += @{'TeamsEnvironmentName'= 'TeamsDOD';}
                       }
                   }
                   Connect-MicrosoftTeams @TeamsParams | Out-Null
               }
               default {
                   throw "Invalid ProductName argument"
               }
           }
       }
       catch {
           Write-Warning "Error establishing a connection with $($Product): $($_.Exception.Message)`n$($_.ScriptStackTrace)"
           $ProdAuthFailed += $Product
           Write-Warning "$($Product) will be omitted from the output because of failed authentication"
       }
   }
   Write-Progress -Activity "Authenticating to each service" -Status "Ready" -Completed
   $ProdAuthFailed
}

function Disconnect-SCuBATenant {
   <#
   .SYNOPSIS
       Disconnect all active M365 connection sessions made by ScubaGear
   .DESCRIPTION
       Forces disconnect of all outstanding open sessions associated with
       M365 product APIs within the current PowerShell session.
       Best used after an ScubaGear run to ensure a new tenant connection is
       used for future ScubaGear runs.
   .Parameter ProductNames
   A list of one or more M365 shortened product names this function will disconnect from. By default this function will disconnect from all possible products ScubaGear can run against.
   .EXAMPLE
   Disconnect-SCuBATenant
   .EXAMPLE
   Disconnect-SCuBATenant -ProductNames teams
   .EXAMPLE
   Disconnect-SCuBATenant -ProductNames aad, exo
   .Functionality
   Public
   #>

   [CmdletBinding()]
   param(
       [ValidateSet("aad", "defender", "exo","powerplatform", "sharepoint", "teams", IgnoreCase = $false)]
       [ValidateNotNullOrEmpty()]
       [string[]]
       $ProductNames = @("aad", "defender", "exo", "powerplatform", "sharepoint", "teams")
   )
   $ErrorActionPreference = "SilentlyContinue"

   try {
       $N = 0
       $Len = $ProductNames.Length

       foreach ($Product in $ProductNames) {
           $N += 1
           $Percent = $N*100/$Len
           Write-Progress -Activity "Disconnecting from each service" -Status "Disconnecting from $($Product); $($n) of $($Len) disconnected." -PercentComplete $Percent
           Write-Verbose "Disconnecting from $Product."
           if (($Product -eq "aad") -or ($Product -eq "sharepoint")) {
               Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null

               if($Product -eq "sharepoint") {
                   Disconnect-SPOService -ErrorAction SilentlyContinue
                   Disconnect-PnPOnline -ErrorAction SilentlyContinue
               }
           }
           elseif ($Product -eq "teams") {
               Disconnect-MicrosoftTeams -Confirm:$false -ErrorAction SilentlyContinue
           }
           elseif ($Product -eq "powerplatform") {
               Remove-PowerAppsAccount -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
           }
           elseif (($Product -eq "exo") -or ($Product -eq "defender")) {
               if($Product -eq "defender") {
                   Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
               }
               Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue -InformationAction SilentlyContinue | Out-Null
           }
           else {
               Write-Warning "Product $Product not recognized, skipping..."
           }
       }
       Write-Progress -Activity "Disconnecting from each service" -Status "Done" -Completed

   } catch [System.InvalidOperationException] {
       # Suppress error due to disconnect from service with no active connection
       continue
   } catch {
       Write-Warning "Could not disconnect from $Product`n: $($_.Exception.Message)`n$($_.ScriptStackTrace)"
   } finally {
       $ErrorActionPreference = "Continue"
   }

}

Export-ModuleMember -Function @(
   'Connect-Tenant',
   'Disconnect-SCuBATenant'
)

# SIG # Begin signature block
# MIIuuQYJKoZIhvcNAQcCoIIuqjCCLqYCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCYRZxj1ufudpce
# DX+ZksDvK67QbHR1LYEKTYfUZpujiaCCE6MwggWQMIIDeKADAgECAhAFmxtXno4h
# MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z
# ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
# IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
# AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z
# G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ
# anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s
# Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL
# 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb
# BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3
# JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c
# AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx
# YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0
# viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL
# T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud
# EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf
# Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk
# aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS
# PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK
# 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB
# cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp
# 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg
# dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri
# RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7
# 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5
# nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3
# i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H
# EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G
# CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
# IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
# ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C
# 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce
# 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da
# E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T
# SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA
# FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh
# D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM
# 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z
# 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05
# huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY
# mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP
# /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T
# AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD
# VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG
# A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV
# HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
# cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN
# BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry
# sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL
# IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf
# Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh
# OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh
# dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV
# 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j
# wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH
# Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC
# XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l
# /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW
# eE4wggdXMIIFP6ADAgECAhAP1uYgxSr4joyBpB/eZOIuMA0GCSqGSIb3DQEBCwUA
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
# ODQgMjAyMSBDQTEwHhcNMjUwMjA4MDAwMDAwWhcNMjYwMTE1MjM1OTU5WjBfMQsw
# CQYDVQQGEwJVUzEdMBsGA1UECBMURGlzdHJpY3Qgb2YgQ29sdW1iaWExEzARBgNV
# BAcTCldhc2hpbmd0b24xDTALBgNVBAoTBENJU0ExDTALBgNVBAMTBENJU0EwggIi
# MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCXm3O0IOQzt0tbPPKAv4IrrzOf
# QjE4Mb9j1zLL1GehaE35ddnoitE7l8OmVEeTLwPH+UpI7DfynUCjLb8HGcsuHO0H
# aUuVFR3FNyvGByYATUTA+bQ9UgcwCoPyL48cDmdqFzheQ/KsC+FhI4uEpYiB/6Jp
# Q0UL0SUVfC8O8+1ioUXAwdMt3G8bT3x6WaEmAbGqM5yC5fd7rKZEmpLzpA6bP2Xc
# QMwi6Jn1m4AvL/jJrXvPyVUK9UlbjobKjiVg6a/UBgFrq8cU7Q1w/e5ijy6XA+aC
# Z7SICqimtCW4wbrvodZL0yFeZIxN9qJ24hvrVGf7P/ANTzkoGHuHLwpMIOjBrpA+
# ig3jBTjY1xE2DYgHWcKHsSHEbOxStk+qHsn2J5i9GK+nwS7GmMqIRaEwy+dbfh6l
# Q2jI4PO6kPk0ePnB3jTD/bEkdbRXpuq3aUAMS4ZSESer+CnzeBLEXvHrVVs4yHrf
# RPmLOX+T43FEf6iAY7Ta3ahn0icLtCtauJ9/jmMigM/l1IfaAF6E/SoCHc6G6S9F
# 1ECU/nBkpThU5u2kufiGWBC8rV2V8D50QERbohnv3yWR5BTG8dX+NYjd7HdctRAj
# 9al3sQ/tdyVgOHUp+9KseYJthuNnh8WCoDeho/GX65QJDSJwh5uDcvNUfpeebANU
# U1GwatZ4l+EWfOc05QIDAQABo4ICAzCCAf8wHwYDVR0jBBgwFoAUaDfg67Y7+F8R
# hvv+YXsIiGX0TkIwHQYDVR0OBBYEFJIsiVnihq62MAlpq96K9lNX9UCGMD4GA1Ud
# IAQ3MDUwMwYGZ4EMAQQBMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNl
# cnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMw
# gbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp
# Z2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5j
# cmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0
# ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMIGUBggrBgEF
# BQcBAQSBhzCBhDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t
# MFwGCCsGAQUFBzAChlBodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl
# cnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJ
# BgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQChGHY/dRc2BtvGT6mHR4bqoakC
# N9hyjDA+bbxJE73T2HgI5wKVmhu2JmFZ/FHmoXE4ngnLnGS+zMEoeTEfzb/MmAxF
# H+Ca/JGMDsbVf+rP+aVc1NkSpUd6u5rsR01Dimcs+pHGwpEUF1HCDFrFcl10Smcj
# b8Z+tPbIETe3yvdRyoJL2Lm6k8wvC7xfgPoMzdbKWRzTCEnVQ+B53vHBSLT4D5wW
# dq3yv6oj2fQ381wZQm16fLIedmiStUYfp0ZICqI3T6UiQ5w/DXYy05Z/1Njqu3PQ
# l2Sy/JLDZc7hBu5YH5ia1G2IFC6S9gN34jm8qhkkoo8kihsxRBbBLiiNB0z/eH7y
# jsNgyRR+Vje51Jcgte18zVQH6fRkl+HDp2nMgdgzShlKYXZzVFQvgmMu76x72P5f
# bOgzmOxCZNZh0AQUo16DdbnGvloqHCbEND2JA/0QpeB0dlWKkWiotu/MaJE8/4uU
# sxw5JSZPj8ya4WnrntJaY73TxXBHSd9CezT7lDShTgB1FkCSAov3aFwqyGH4hC+2
# MGp3Wzn03rkqVCzjmgNSIkCxQzJ+hEIvbk6GVK2yk+Q9eZQCkjRKY+EYwJNDsB9I
# w75dWMsi2S9PFBEkKZYZFgxwVaBvnWgrfxlZMOooNADSdmq5fvTH/tjR3vIEd4QP
# Dlzb9f7QLX+cvb0MjjGCGmwwghpoAgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNV
# BAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0
# IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQD9bmIMUq+I6M
# gaQf3mTiLjANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgACh
# AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM
# BgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCDZflC+Zm+GSJK2SOs+z3U4AEdh
# M12iid/9lnnAjmV/iDANBgkqhkiG9w0BAQEFAASCAgAFsTIyDQy86UWtHliMGSjy
# Tsr8Y5GgyJ3zDEB0gfAGzsy6MBFxuR/HIOBQwQ/1b55TuHrJOMi4vp/VJuKR2hCn
# 4W4rv6kxz2eatYVfXYzhvTnfJhgqpXPB7zsvKBYGIY1UWx6NsSONktJcVYn4q3Nb
# YACQuXmBjS1dF9Z1odeDsIPfEHIG5x85r6aduMi4evRbxKcF5vg/QrQIrph+kaNU
# 8YiSEplRAy7ld2Z0ki1cITdH8PwwEFVwcOqywp5zuW66O6Eh95WfrMtR84tWmUGr
# RxcLabMmdY4WAJVq5J4btEB26NPxVWRo83QVyRHIfNOgTgJwN87kil2mIkApgQWf
# OwXKMLSvrPTf/AjwtGbCDXZJtQSsasujwg9kbG8M4QN4zQvkc+regdhe/2Ywfmiz
# h50nAzD9LJL3Uk6SslMJDQNVxQ9ELojJeCjxhWSk5dAS4482puKdvIJOFgM5xKjr
# j5n79kbvhNkD5maNljHqJi3O83hp/zPteQiWXkCu/fSbtMH1HqjjihgcCJZKi4nq
# rRvfh3N37Pv+4JbGZ/iW3IocP8uPj5q0X/Z9zwci5knJPd5u4cISS1d/9VHsIGZy
# OOhyVxkFnErsdSiwapyrkyt9MoXFVsuUe4j0gzICKa2UpVA5YNcQUs1vQtEqpUcf
# oSCws65kgtrouzrnsSMGO6GCFzkwghc1BgorBgEEAYI3AwMBMYIXJTCCFyEGCSqG
# SIb3DQEHAqCCFxIwghcOAgEDMQ8wDQYJYIZIAWUDBAIBBQAwdwYLKoZIhvcNAQkQ
# AQSgaARmMGQCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFlAwQCAQUABCCwZVIc4/SQ
# 9ohgJB/mlXG7JM8QZIQCHjNe3brGFjwlFAIQP8vKLyPewzCB/0Iibyo5VxgPMjAy
# NTA0MTQyMDM5MTVaoIITAzCCBrwwggSkoAMCAQICEAuuZrxaun+Vh8b56QTjMwQw
# DQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0
# LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hB
# MjU2IFRpbWVTdGFtcGluZyBDQTAeFw0yNDA5MjYwMDAwMDBaFw0zNTExMjUyMzU5
# NTlaMEIxCzAJBgNVBAYTAlVTMREwDwYDVQQKEwhEaWdpQ2VydDEgMB4GA1UEAxMX
# RGlnaUNlcnQgVGltZXN0YW1wIDIwMjQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
# ggIKAoICAQC+anOf9pUhq5Ywultt5lmjtej9kR8YxIg7apnjpcH9CjAgQxK+CMR0
# Rne/i+utMeV5bUlYYSuuM4vQngvQepVHVzNLO9RDnEXvPghCaft0djvKKO+hDu6O
# bS7rJcXa/UKvNminKQPTv/1+kBPgHGlP28mgmoCw/xi6FG9+Un1h4eN6zh926SxM
# e6We2r1Z6VFZj75MU/HNmtsgtFjKfITLutLWUdAoWle+jYZ49+wxGE1/UXjWfISD
# mHuI5e/6+NfQrxGFSKx+rDdNMsePW6FLrphfYtk/FLihp/feun0eV+pIF496OVh4
# R1TvjQYpAztJpVIfdNsEvxHofBf1BWkadc+Up0Th8EifkEEWdX4rA/FE1Q0rqViT
# bLVZIqi6viEk3RIySho1XyHLIAOJfXG5PEppc3XYeBH7xa6VTZ3rOHNeiYnY+V4j
# 1XbJ+Z9dI8ZhqcaDHOoj5KGg4YuiYx3eYm33aebsyF6eD9MF5IDbPgjvwmnAalNE
# eJPvIeoGJXaeBQjIK13SlnzODdLtuThALhGtyconcVuPI8AaiCaiJnfdzUcb3dWn
# qUnjXkRFwLtsVAxFvGqsxUA2Jq/WTjbnNjIUzIs3ITVC6VBKAOlb2u29Vwgfta8b
# 2ypi6n2PzP0nVepsFk8nlcuWfyZLzBaZ0MucEdeBiXL+nUOGhCjl+QIDAQABo4IB
# izCCAYcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAww
# CgYIKwYBBQUHAwgwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMB8G
# A1UdIwQYMBaAFLoW2W1NhS9zKXaaL3WMaiCPnshvMB0GA1UdDgQWBBSfVywDdw4o
# FZBmpWNe7k+SH3agWzBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsMy5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0YW1w
# aW5nQ0EuY3JsMIGQBggrBgEFBQcBAQSBgzCBgDAkBggrBgEFBQcwAYYYaHR0cDov
# L29jc3AuZGlnaWNlcnQuY29tMFgGCCsGAQUFBzAChkxodHRwOi8vY2FjZXJ0cy5k
# aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0
# YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQA9rR4fdplb4ziEEkfZQ5H2
# EdubTggd0ShPz9Pce4FLJl6reNKLkZd5Y/vEIqFWKt4oKcKz7wZmXa5VgW9B76k9
# NJxUl4JlKwyjUkKhk3aYx7D8vi2mpU1tKlY71AYXB8wTLrQeh83pXnWwwsxc1Mt+
# FWqz57yFq6laICtKjPICYYf/qgxACHTvypGHrC8k1TqCeHk6u4I/VBQC9VK7iSpU
# 5wlWjNlHlFFv/M93748YTeoXU/fFa9hWJQkuzG2+B7+bMDvmgF8VlJt1qQcl7YFU
# MYgZU1WM6nyw23vT6QSgwX5Pq2m0xQ2V6FJHu8z4LXe/371k5QrN9FQBhLLISZi2
# yemW0P8ZZfx4zvSWzVXpAb9k4Hpvpi6bUe8iK6WonUSV6yPlMwerwJZP/Gtbu3CK
# ldMnn+LmmRTkTXpFIEB06nXZrDwhCGED+8RsWQSIXZpuG4WLFQOhtloDRWGoCwwc
# 6ZpPddOFkM2LlTbMcqFSzm4cd0boGhBq7vkqI1uHRz6Fq1IX7TaRQuR+0BGOzISk
# cqwXu7nMpFu3mgrlgbAW+BzikRVQ3K2YHcGkiKjA4gi4OA/kz1YCsdhIBHXqBzR0
# /Zd2QwQ/l4Gxftt/8wY3grcc/nS//TVkej9nmUYu83BDtccHHXKibMs/yXHhDXNk
# oPIdynhVAku7aRZOwqw6pDCCBq4wggSWoAMCAQICEAc2N7ckVHzYR6z9KGYqXlsw
# DQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0
# IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNl
# cnQgVHJ1c3RlZCBSb290IEc0MB4XDTIyMDMyMzAwMDAwMFoXDTM3MDMyMjIzNTk1
# OVowYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYD
# VQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFt
# cGluZyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMaGNQZJs8E9
# cklRVcclA8TykTepl1Gh1tKD0Z5Mom2gsMyD+Vr2EaFEFUJfpIjzaPp985yJC3+d
# H54PMx9QEwsmc5Zt+FeoAn39Q7SE2hHxc7Gz7iuAhIoiGN/r2j3EF3+rGSs+Qtxn
# jupRPfDWVtTnKC3r07G1decfBmWNlCnT2exp39mQh0YAe9tEQYncfGpXevA3eZ9d
# rMvohGS0UvJ2R/dhgxndX7RUCyFobjchu0CsX7LeSn3O9TkSZ+8OpWNs5KbFHc02
# DVzV5huowWR0QKfAcsW6Th+xtVhNef7Xj3OTrCw54qVI1vCwMROpVymWJy71h6aP
# TnYVVSZwmCZ/oBpHIEPjQ2OAe3VuJyWQmDo4EbP29p7mO1vsgd4iFNmCKseSv6De
# 4z6ic/rnH1pslPJSlRErWHRAKKtzQ87fSqEcazjFKfPKqpZzQmiftkaznTqj1QPg
# v/CiPMpC3BhIfxQ0z9JMq++bPf4OuGQq+nUoJEHtQr8FnGZJUlD0UfM2SU2LINIs
# VzV5K6jzRWC8I41Y99xh3pP+OcD5sjClTNfpmEpYPtMDiP6zj9NeS3YSUZPJjAw7
# W4oiqMEmCPkUEBIDfV8ju2TjY+Cm4T72wnSyPx4JduyrXUZ14mCjWAkBKAAOhFTu
# zuldyF4wEr1GnrXTdrnSDmuZDNIztM2xAgMBAAGjggFdMIIBWTASBgNVHRMBAf8E
# CDAGAQH/AgEAMB0GA1UdDgQWBBS6FtltTYUvcyl2mi91jGogj57IbzAfBgNVHSME
# GDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0l
# BAwwCgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRw
# Oi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRz
# LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8
# MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0
# ZWRSb290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATAN
# BgkqhkiG9w0BAQsFAAOCAgEAfVmOwJO2b5ipRCIBfmbW2CFC4bAYLhBNE88wU86/
# GPvHUF3iSyn7cIoNqilp/GnBzx0H6T5gyNgL5Vxb122H+oQgJTQxZ822EpZvxFBM
# Yh0MCIKoFr2pVs8Vc40BIiXOlWk/R3f7cnQU1/+rT4osequFzUNf7WC2qk+RZp4s
# nuCKrOX9jLxkJodskr2dfNBwCnzvqLx1T7pa96kQsl3p/yhUifDVinF2ZdrM8HKj
# I/rAJ4JErpknG6skHibBt94q6/aesXmZgaNWhqsKRcnfxI2g55j7+6adcq/Ex8HB
# anHZxhOACcS2n82HhyS7T6NJuXdmkfFynOlLAlKnN36TU6w7HQhJD5TNOXrd/yVj
# mScsPT9rp/Fmw0HNT7ZAmyEhQNC3EyTN3B14OuSereU0cZLXJmvkOHOrpgFPvT87
# eK1MrfvElXvtCl8zOYdBeHo46Zzh3SP9HSjTx/no8Zhf+yvYfvJGnXUsHicsJttv
# FXseGYs2uJPU5vIXmVnKcPA3v5gA3yAWTyf7YGcWoWa63VXAOimGsJigK+2VQbc6
# 1RWYMbRiCQ8KvYHZE/6/pNHzV9m8BPqC3jLfBInwAM1dwvnQI38AC+R2AibZ8GV2
# QqYphwlHK+Z/GqSFD/yYlvZVVCsfgPrA8g4r5db7qS9EFUrnEw4d2zc4GqEr9u3W
# fPwwggWNMIIEdaADAgECAhAOmxiO+dAt5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUA
# MGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT
# EHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQg
# Um9vdCBDQTAeFw0yMjA4MDEwMDAwMDBaFw0zMTExMDkyMzU5NTlaMGIxCzAJBgNV
# BAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp
# Y2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIw
# DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL/mkHNo3rvkXUo8MCIwaTPswqcl
# LskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/zG6Q4FutWxpdtHauyefLKEdLkX9YF
# PFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZanMylNEQRBAu34LzB4TmdDttceIt
# DBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7sWxq868nPzaw0QF+xembud8hIqGZX
# V59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1
# ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfbBHMqbpEBfCFM1LyuGwN1XXhm2Tox
# RJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3JFxGj2T3wWmIdph2PVldQnaHiZdp
# ekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF
# 30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqxYxhElRp2Yn72gLD76GSmM9GJB+G9
# t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0viastkF13nqsX40/ybzTQRESW+UQ
# UOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aLT8LWRV+dIPyhHsXAj6KxfgommfXk
# aS+YHS312amyHeUbAgMBAAGjggE6MIIBNjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
# DgQWBBTs1+OC0nFdZEzfLmc/57qYrhwPTzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEt
# UYunpyGd823IDzAOBgNVHQ8BAf8EBAMCAYYweQYIKwYBBQUHAQEEbTBrMCQGCCsG
# AQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0
# dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RD
# QS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29t
# L0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDARBgNVHSAECjAIMAYGBFUdIAAw
# DQYJKoZIhvcNAQEMBQADggEBAHCgv0NcVec4X6CjdBs9thbX979XB72arKGHLOyF
# XqkauyL4hxppVCLtpIh3bb0aFPQTSnovLbc47/T/gLn4offyct4kvFIDyE7QKt76
# LVbP+fT3rDB6mouyXtTP0UNEm0Mh65ZyoUi0mcudT6cGAxN3J0TU53/oWajwvy8L
# punyNDzs9wPHh6jSTEAZNUZqaVSwuKFWjuyk1T3osdz9HNj0d1pcVIxv76FQPfx2
# CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPFmCLBsln1VWvPJ6tsds5vIy30fnFqI2si
# /xK4VC0nftg62fC2h5b9W9FcrBjDTZ9ztwGpn1eqXijiuZQxggN2MIIDcgIBATB3
# MGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UE
# AxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBp
# bmcgQ0ECEAuuZrxaun+Vh8b56QTjMwQwDQYJYIZIAWUDBAIBBQCggdEwGgYJKoZI
# hvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNTA0MTQyMDM5
# MTVaMCsGCyqGSIb3DQEJEAIMMRwwGjAYMBYEFNvThe5i29I+e+T2cUhQhyTVhltF
# MC8GCSqGSIb3DQEJBDEiBCDFFOdjOqVf3td9feftUsSEzLHzMfxpVaWzm7jIOl+6
# gDA3BgsqhkiG9w0BCRACLzEoMCYwJDAiBCB2dp+o8mMvH0MLOiMwrtZWdf7Xc9sF
# 1mW5BZOYQ4+a2zANBgkqhkiG9w0BAQEFAASCAgCMLYb9AUH4jtMdE7z5GCDJ2haK
# R2uyaJLXjDbjESKEdpiMbgdm/HKhkJU+RgL87A2O443jbwYJsbFGoj9cTYXj649h
# yi3O9Mon0U63hDQekfk1yKtQ9TOE0Fmy7RnRD24KWhU36dQeIU9qanHxrjTFQdSr
# xxqyLR+ahVe2uIys2GBMyfGWTcgYTEpmkTtStdcitUuUAgDctYUWW/iz1cuqKaxa
# NumP5sV6AP0CqT+u0nsNf0+VY3YCWqMqlNO6XCb730RR9mzDsz5GLITuLugVjlhO
# i4PcqBwoR9G25AbLndnL+27vAdq62X0rA5LKWo0J4A2OYqO/S/Sph3e/txlZHbX8
# AFeLTXnjCFO30LcXWL+BcuHxCvLC8GYsaLL4OeQrTPgfDvxlMme1k4/1xp9/3bGS
# utmnNiQLi0trm7mOMmsLGnBkZptVbAaDthYe1JDwoc/pVX/Rf9uVrOyTQArKRdtZ
# DeTwfuir0F/4wI1Db3uBGBXFVtVrTnoOQedrAmA8wAcZWX/dx1iK69cw1Z4xagzH
# rHDmZmFmPA0U0xnXjrAPRniQahJihY3eoBNpYyeaO6AQozFXe4/5u8nJxZj4umqq
# UpyI+8XwX7ZdaOLcjUJagx8bSjGyDklF2yh7YfOOAYdAhu0954HmRXt7hTP+aW0Y
# NGprgXWRmta3ScfORw==
# SIG # End signature block