Modules/Providers/ExportEXOProvider.psm1

function Export-EXOProvider {
    <#
    .Description
    Gets the Exchange Online (EXO) settings that are relevant
    to the SCuBA EXO baselines using the EXO PowerShell Module
    .Functionality
    Internal
    #>


    [CmdletBinding()]
    [OutputType([String])]
    param()

    # Manually importing the module name here to bypass cmdlet name conflicts
    # There are conflicting PowerShell Cmdlet names in EXO and Power Platform
    Import-Module ExchangeOnlineManagement

    Import-Module $PSScriptRoot/ProviderHelpers/CommandTracker.psm1
    $Tracker = Get-CommandTracker

    <#
    MS.EXO.1.1v1
    #>

    $RemoteDomains = ConvertTo-Json @($Tracker.TryCommand("Get-RemoteDomain"))

    <#
    MS.EXO.2.1v1 SPF
    #>

    $domains = $Tracker.TryCommand("Get-AcceptedDomain")
    $SPFRecords = ConvertTo-Json @($Tracker.TryCommand("Get-ScubaSpfRecord", @{"Domains"=$domains})) -Depth 3

    <#
    MS.EXO.3.1v1 DKIM
    #>

    $DKIMConfig = ConvertTo-Json @($Tracker.TryCommand("Get-DkimSigningConfig"))
    $DKIMRecords = ConvertTo-Json @($Tracker.TryCommand("Get-ScubaDkimRecord", @{"Domains"=$domains})) -Depth 3

    <#
    MS.EXO.4.1v1 DMARC
    #>

    $DMARCRecords = ConvertTo-Json @($Tracker.TryCommand("Get-ScubaDmarcRecord", @{"Domains"=$domains})) -Depth 3

    <#
    MS.EXO.5.1v1
    #>

    $TransportConfig = ConvertTo-Json @($Tracker.TryCommand("Get-TransportConfig"))

    <#
    MS.EXO.6.1v1
    #>

    $SharingPolicy = ConvertTo-Json @($Tracker.TryCommand("Get-SharingPolicy"))

    <#
    MS.EXO.7.1v1
    #>

    $TransportRules = ConvertTo-Json @($Tracker.TryCommand("Get-TransportRule"))

    <#
    MS.EXO.12.1v1
    #>

    $ConnectionFilter = ConvertTo-Json @($Tracker.TryCommand("Get-HostedConnectionFilterPolicy"))

    <#
    MS.EXO.13.1v1
    #>

    $Config = $Tracker.TryCommand("Get-OrganizationConfig") | Select-Object Name, DisplayName, AuditDisabled
    $Config = ConvertTo-Json @($Config)

    # Used in the reporter to check successful cmdlet invocation
    $SuccessfulCommands = ConvertTo-Json @($Tracker.GetSuccessfulCommands())
    $UnSuccessfulCommands = ConvertTo-Json @($Tracker.GetUnSuccessfulCommands())

    # Note the spacing and the last comma in the json is important
    $json = @"
    "remote_domains": $RemoteDomains,
    "spf_records": $SPFRecords,
    "dkim_config": $DKIMConfig,
    "dkim_records": $DKIMRecords,
    "dmarc_records": $DMARCRecords,
    "transport_config": $TransportConfig,
    "sharing_policy": $SharingPolicy,
    "transport_rule": $TransportRules,
    "conn_filter": $ConnectionFilter,
    "org_config": $Config,
    "exo_successful_commands": $SuccessfulCommands,
    "exo_unsuccessful_commands": $UnSuccessfulCommands,
"@


    $json
}

function Get-EXOTenantDetail {
    <#
    .Description
    Gets the tenant details using the EXO PowerShell Module
    .Functionality
    Internal
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateSet("commercial", "gcc", "gcchigh", "dod", IgnoreCase = $false)]
        [ValidateNotNullOrEmpty()]
        [string]
        $M365Environment
    )
    try {
        Import-Module ExchangeOnlineManagement
        $OrgConfig = Get-OrganizationConfig -ErrorAction "Stop"
        $DomainName = $OrgConfig.Name
        $TenantId = "Error retrieving Tenant ID"
        $Uri = "https://login.microsoftonline.com/$($DomainName)/.well-known/openid-configuration"

        if (($M365Environment -eq "gcchigh") -or ($M365Environment -eq "dod")) {
            $TLD = ".us"
            $Uri = "https://login.microsoftonline$($TLD)/$($DomainName)/.well-known/openid-configuration"
        }
        try {
            $Content = (Invoke-WebRequest -Uri $Uri -UseBasicParsing -ErrorAction "Stop").Content
            $TenantId = (ConvertFrom-Json $Content).token_endpoint.Split("/")[3]
        }
        catch {
            Write-Warning "Unable to retrieve EXO Tenant ID with URI. This may be caused by proxy error see 'Running the Script Behind Some Proxies' in the README for a solution. $($_)"
        }

        $EXOTenantInfo = @{
            "DisplayName"= $OrgConfig.DisplayName;
            "DomainName" = $DomainName;
            "TenantId" = $TenantId;
            "EXOAdditionalData" = "Unable to safely retrieve due to EXO API changes";
        }
        $EXOTenantInfo = ConvertTo-Json @($EXOTenantInfo) -Depth 4
        $EXOTenantInfo
    }
    catch {
        Write-Warning "Error retrieving Tenant details using Get-EXOTenantDetail $($_)"
        $EXOTenantInfo = @{
            "DisplayName" = "Error retrieving Display name";
            "DomainName" = "Error retrieving Domain name";
            "TenantId" = "Error retrieving Tenant ID";
            "EXOAdditionalData" = "Error retrieving additional data";
        }
        $EXOTenantInfo = ConvertTo-Json @($EXOTenantInfo) -Depth 4
        $EXOTenantInfo
    }
}

# A $script:scoped variable used to indicate the preferred DoH server.
# Initialize to empty string to indicate that we don't yet know the
# preferred server. Will be set when the Select-DohServer function is
# called.
$DohServer = ""

function Select-DohServer {
    <#
    .Description
    Iterates through several DoH servers. Returns the first successful server. If none are successful, returns $null.
    .Functionality
    Internal
    #>

    $DoHServers = @("cloudflare-dns.com", "[2606:4700:4700::1111]", "1.1.1.1")
    $PreferredServer = $null
    foreach ($Server in $DoHServers) {
        try {
            # Attempt to resolve a.root-servers.net over DoH. The domain chosen is somewhat
            # arbitrary, as we don't care what the answer is, only if the query succeeds/fails.
            # a.root-servers.net, the address of one of the DNS root servers, was chosen as a
            # benign, highly-available domain.
            $Uri = "https://$($Server)/dns-query?name=a.root-servers.net"
            Invoke-WebRequest -Headers @{"accept"="application/dns-json"} -Uri $Uri `
                -TimeoutSec 2 -UseBasicParsing -ErrorAction "Stop" | Out-Null
            # No error was thrown, return this server
            $PreferredServer = $Server
            break
        }
        catch {
            # This server didn't work, try the next one
            continue
        }
    }
    $PreferredServer
}

function Invoke-RobustDnsTxt {
    <#
    .Description
    Requests the TXT record for the given qname. First tries to make the query over traditional DNS
    but retries over DoH in the event of failure.
    .Parameter Qname
    The fully-qualified domain name to request.
    .Parameter MaxTries
    The number of times to retry each kind of query. If all queries are unsuccessful, the traditional
    queries and the DoH queries will each be made $MaxTries times. Default is 2.
    .Functionality
    Internal
    #>

    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Qname,

        [Parameter(Mandatory=$false)]
        [ValidateRange(1, [int]::MaxValue)]
        [int]
        $MaxTries = 2
    )
    $Answers = @()
    $LogEntries = @()

    $TryNumber = 0
    $Success = $false
    $TradEmpty = $false
    while ($TryNumber -lt $MaxTries) {
        $TryNumber += 1
        try {
            $Response = Resolve-DnsName $Qname txt -ErrorAction Stop | Where-Object {$_.Section -eq "Answer"}
            if ($Response.Strings.Length -gt 0) {
                # We got our answer, so break out of the retry loop and set $Success to $true, no
                # need to retry the traditional query or retry with DoH.
                $LogEntries += @{
                    "query_name"=$Qname;
                    "query_method"="traditional";
                    "query_result"="Query returned $($Response.Strings.Length) txt records"
                }
                $Answers += $Response.Strings
                $Success = $true
                break
            }
            else {
                # The answer section was empty. This usually means that while the domain exists, but
                # there are no records of the requested type. No need to retry the traditional query,
                # this was not a transient failure. Don't set $Success to $true though, as we want to
                # retry this query from a public resolver, in case the internal DNS server returns a
                # different answer than what is served to the public (i.e., split horizon DNS).
                $LogEntries += @{
                    "query_name"=$Qname;
                    "query_method"="traditional";
                    "query_result"="Query returned 0 txt records"
                }
                $TradEmpty = $true
                break
            }
        }
        catch {
            if ($_.FullyQualifiedErrorId -eq "DNS_ERROR_RCODE_NAME_ERROR,Microsoft.DnsClient.Commands.ResolveDnsName") {
                # The server returned NXDomain, no need to retry the traditional query or retry with
                # DoH, this was not a transient failure. Break out of loop and set $Success to $true
                $LogEntries += @{
                    "query_name"=$Qname;
                    "query_method"="traditional";
                    "query_result"="Query returned NXDomain"
                }
                $Success = $True
                break
            }
            else {
                # The query failed, possibly a transient failure. Retry if we haven't reached $MaxsTries.
                $LogEntries += @{
                    "query_name"=$Qname;
                    "query_method"="traditional";
                    "query_result"="Query resulted in exception, $($_.FullyQualifiedErrorId)"
                }
            }
        }
    }

    if (-not $Success) {
        # The traditional DNS query(ies) failed. Retry with DoH
        if ($script:DohServer -eq "") {
            # We haven't determined if DoH is available yet, select the first server that works
            $script:DohServer = Select-DohServer
        }
        if ($null -eq $script:DohServer) {
            # None of the DoH servers are accessible
            $LogEntries += @{"query_name"=$Qname; "query_method"="DoH"; "query_result"="NA, DoH servers unreachable"}
        }
        else {
            # DoH is available, query for the domain
            $TryNumber = 0
            while ($TryNumber -lt $MaxTries) {
                $TryNumber += 1
                try {
                    $Uri = "https://$($script:DohServer)/dns-query?name=$($Qname)&type=txt"
                    $Headers = @{"accept"="application/dns-json"}
                    $RawResponse = $(Invoke-WebRequest -Headers $Headers -Uri $Uri -UseBasicParsing -ErrorAction "Stop").RawContent
                    $ResponseLines = $RawResponse -Split "`n"
                    $LastLine = $ResponseLines[$ResponseLines.Length - 1]
                    $ResponseBody = ConvertFrom-Json $LastLine
                    if ($ResponseBody.Status -eq 0) {
                        # 0 indicates there was no error
                        $LogEntries += @{
                            "query_name"=$Qname;
                            "query_method"="DoH";
                            "query_result"="Query returned $($ResponseBody.Answer.data.Length) txt records"
                        }
                        $Answers += ($ResponseBody.Answer.data | ForEach-Object {$_.Replace('"', '')})
                        $Success = $true
                        break
                    }
                    elseif ($ResponseBody.Status -eq 3) {
                        # 3 indicates NXDomain. The DNS query succeeded, but the domain did not exist.
                        # Set $Success to $true, because event though the domain does not exist, the
                        # query succeeded, and this came from an external resolver so split horizon is
                        # not an issue here.
                        $LogEntries += @{
                            "query_name"=$Qname;
                            "query_method"="DoH";
                            "query_result"="Query returned NXDomain"
                        }
                        $Success = $true
                        break
                    }
                    else {
                        # The remainder of the response codes indicate that the query did not succeed.
                        # Retry if we haven't reached $MaxTries.
                        $LogEntries += @{
                            "query_name"=$Qname;
                            "query_method"="DoH";
                            "query_result"="Query returned response code $($ResponseBody.Status)"
                        }
                    }
                }
                catch {
                    # The DoH query failed, likely due to a network issue. Retry if we haven't reached
                    # $MaxTries.
                    $LogEntries += @{
                        "query_name"=$Qname;
                        "query_method"="DoH";
                        "query_result"="Query resulted in exception, $($_.FullyQualifiedErrorId)"
                    }
                }
            }
        }
    }

    # There are three possible outcomes of this function:
    # - Full confidence: we know conclusively that the domain exists or not, either via a non-empty
    # answer from traditional DNS or an answer from DoH.
    # - Medium confidence: domain likely doesn't exist, but there is some doubt (empty answer from
    # traditonal DNS and DoH failed).
    # No confidence: all queries failed. Throw an exception in this case.
    if ($Success) {
        @{"Answers" = $Answers; "HighConfidence" = $true; "LogEntries" = $LogEntries}
    }
    elseif ($TradEmpty) {
        @{"Answers" = $Answers; "HighConfidence" = $false; "LogEntries" = $LogEntries}
    }
    else {
        $Log = ($LogEntries | ForEach-Object {ConvertTo-Json $_ -Compress}) -Join "`n"
        throw "Failed to resolve $($Qname). `n$($Log)"
    }
}

function Get-ScubaSpfRecord {
    <#
    .Description
    Gets the SPF records for each domain in $Domains
    .Functionality
    Internal
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.Object[]]
        $Domains
    )

    $SPFRecords = @()
    $NLowConf = 0

    foreach ($d in $Domains) {
        $Response = Invoke-RobustDnsTxt $d.DomainName
        if (-not $Response.HighConfidence) {
            $NLowConf += 1
        }
        $DomainName = $d.DomainName
        $SPFRecords += [PSCustomObject]@{
            "domain" = $DomainName;
            "rdata" = $Response.Answers;
            "log" = $Response.LogEntries;
        }
    }

    if ($NLowConf -gt 0) {
        Write-Warning "Get-ScubaSpfRecord: for $($NLowConf) domain(s), the tradtional DNS queries returned an empty answer section and the DoH queries failed. Will assume SPF not configured, but can't guarantee that failure isn't due to something like split horizon DNS. See ProviderSettingsExport.json under 'spf_records' for more details."
    }
    $SPFRecords
}

function Get-ScubaDkimRecord {
    <#
    .Description
    Gets the DKIM records for each domain in $Domains
    .Functionality
    Internal
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.Object[]]
        $Domains
    )

    $DKIMRecords = @()
    $NLowConf = 0

    foreach ($d in $domains) {
        $DomainName = $d.DomainName
        $selectors = "selector1", "selector2"
        $selectors += "selector1.$DomainName" -replace "\.", "-"
        $selectors += "selector2.$DomainName" -replace "\.", "-"

        $LogEntries = @()
        foreach ($s in $selectors) {
            $Response = Invoke-RobustDnsTxt "$s._domainkey.$DomainName"
            $LogEntries += $Response.LogEntries
            if ($Response.Answers.Length -eq 0) {
                # The DKIM record does not exist with this selector, we need to try again with
                # a different one
                continue
            }
            else {
                # The DKIM record exists with this selector, no need to try the rest
                break
            }
        }

        if (-not $Response.HighConfidence) {
            $NLowConf += 1
        }

        $DKIMRecords += [PSCustomObject]@{
            "domain" = $DomainName;
            "rdata" = $Response.Answers;
            "log" = $LogEntries;
        }
    }

    if ($NLowConf -gt 0) {
        Write-Warning "Get-ScubaDkimRecord: for $($NLowConf) domain(s), the tradtional DNS queries returned an empty answer section and the DoH queries failed. Will assume DKIM not configured, but can't guarantee that failure isn't due to something like split horizon DNS. See ProviderSettingsExport.json under 'dkim_records' for more details."
    }
    $DKIMRecords
}

function Get-ScubaDmarcRecord {
    <#
    .Description
    Gets the DMARC records for each domain in $Domains
    .Functionality
    Internal
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.Object[]]
        $Domains
    )

    $DMARCRecords = @()
    $NLowConf = 0

    foreach ($d in $Domains) {
    $LogEntries = @()
        # First check to see if the record is available at the full domain level
        $DomainName = $d.DomainName
        $Response = Invoke-RobustDnsTxt "_dmarc.$DomainName"
        $LogEntries += $Response.LogEntries
        if ($Response.Answers.Length -eq 0) {
            # The domain does not exist. If the record is not available at the full domain
            # level, we need to check at the organizational domain level.
            $Labels = $d.DomainName.Split(".")
            $Labels = $d.DomainName.Split(".")
            $OrgDomain = $Labels[-2] + "." + $Labels[-1]
            $Response = Invoke-RobustDnsTxt "_dmarc.$OrgDomain"
            $LogEntries += $Response.LogEntries
        }

        $DomainName = $d.DomainName
        if (-not $Response.HighConfidence) {
            $NLowConf += 1
        }
        $DMARCRecords += [PSCustomObject]@{
            "domain" = $DomainName;
            "rdata" = @($Response.Answers);
            "log" = $LogEntries;
        }
    }

    if ($NLowConf -gt 0) {
        Write-Warning "Get-ScubaDmarcRecord: for $($NLowConf) domain(s), the tradtional DNS queries returned an empty answer section and the DoH queries failed. Will assume DMARC not configured, but can't guarantee that failure isn't due to something like split horizon DNS. See ProviderSettingsExport.json under 'dmarc_records' for more details."
    }
    $DMARCRecords
}
# SIG # Begin signature block
# MIIuuQYJKoZIhvcNAQcCoIIuqjCCLqYCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBujA5Yg45tSk65
# F+7bt2RPTr+wGT6c7jvA1n/vJgmc5KCCE6MwggWQMIIDeKADAgECAhAFmxtXno4h
# 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
# eE4wggdXMIIFP6ADAgECAhANkQ8dPvvR0q3Ytt4H0T3aMA0GCSqGSIb3DQEBCwUA
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
# ODQgMjAyMSBDQTEwHhcNMjQwMTMwMDAwMDAwWhcNMjUwMTI5MjM1OTU5WjBfMQsw
# CQYDVQQGEwJVUzEdMBsGA1UECBMURGlzdHJpY3Qgb2YgQ29sdW1iaWExEzARBgNV
# BAcTCldhc2hpbmd0b24xDTALBgNVBAoTBENJU0ExDTALBgNVBAMTBENJU0EwggIi
# MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCT1y7uJCQax8JfiDEYgpiU9URj
# EXCTRqtZbDALM9rPUudiuM3mj6A1SUSAAWYv6DTsvGPvxyMI2Idg0mQunl4Ms9DJ
# yVwe5k4+Anj/73Nx1AbOPYP8xRZcD10FkctKGhV0PzvrDcwU15hsQWtiepFgg+bX
# fHkGMeu426oc69f43vKE43DiqKTf0/UBX/qgpj3JZvJ3zc1kilBOv4sBCksfCjbW
# tLZD0tqAgBsNPo3Oy5mQG31E1eZdTNvrdTnEXacSwb3k615z7mHy7nqBUkOruZ9E
# tnvC2qla+uL3ks91O/e/LnKzH9Lj1JmEBf6jwPN/MYR9Dymni4Mi3AQ8mpQMyFmi
# XcSHymibSNbtTMavpdBWjFfrcvPETX7krROUOoLzMQmNgHArceSh55tgvDRdSU5c
# WK3BTvK3l3mgCdgjre7XGYxV3W8apyxk5+RKfHdbv9cpRwpSuDnI8sHeqmB3fnfo
# Cr1PPu4WhKegt20CobhDVybiBdhDVqUdR53ful4N/coQOEHDrIExB5nJf9Pvdrza
# DyIGKAMIXD79ba5/rQEo+2cA66oJkPlvB5hEGI/jtDcYwDBgalbwB7Kc8zAAhl6+
# JvHfYpXOkppSfEQbaRXZI+LGXWQAFa5pJDfDEAyZSXprStgw594sWUOysp+UOxFe
# kSA4mBr0o1jVpdaulwIDAQABo4ICAzCCAf8wHwYDVR0jBBgwFoAUaDfg67Y7+F8R
# hvv+YXsIiGX0TkIwHQYDVR0OBBYEFAmyTB5bcWyA+8+rq540jPRLJ1nYMD4GA1Ud
# IAQ3MDUwMwYGZ4EMAQQBMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNl
# cnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMw
# gbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp
# Z2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5j
# cmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0
# ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMIGUBggrBgEF
# BQcBAQSBhzCBhDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t
# MFwGCCsGAQUFBzAChlBodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl
# cnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJ
# BgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQAh2Jnt9IPoBvOQlYQUlCP9iJ5y
# XAvEWe1camOwedqMZsHEPpT2yd6+fMzPZmV3/bYJgaN2OrDS1snf62S7yc+AulVw
# PAXSp1lSAiFEbZ6PFEdEBIag9B65Mp/cvRtJsIWQIc//jWqFMHpkU6r3MW9YARRu
# vaIf5/0qlM4VEwn3lTf+jJdxhhyoOFTWWd3BrlMPcT06z6F6hFfyycQkZ3Y9wEJ3
# uOU9bCNLZL1HCjlKT+oI0WsgeRdbe2sYrnvv9NmDY9oEi8PEq+DGjiTgLbY5OcAX
# uUogPPw6gbcuNn8Hq6FFKPIQxaksB8dF8Gw4m2lQoUWESPRF8Zaq9lmZN3+QzA79
# yskfJtAFqz3gUP5wJBdNfi/u1sGbLI0QnJQkIKfFuz7DfDPldw0gIl05BIYwZBmj
# TpFRu1/+gIlP1Ul4L/wt9Lxk6pglObLsdxHP2UQrG30JaUN0gv3xZMBBByHGVVTe
# cyU4qwJ0ulMdv/kjHwh+m58uOF8gHXLfyBmOjYpohN3+l0rS0qdArZMNSmLTA7N8
# n3V3AZLKB//1yhPt++gR4pCFdXmgwYDDLRxjlV0cMsG1UeSQUdI0aieh/grg5TQO
# CergVXS5h3sz5U0ZQPWND41LJhA0gF2OGZNHdUc9+0dwTsfxAERrjaTdeZp0/rdZ
# 9iGBoiRsS4U86S8xkDGCGmwwghpoAgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNV
# BAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0
# IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQDZEPHT770dKt
# 2LbeB9E92jANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgACh
# AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM
# BgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCCACc5NMz8ySKj8yhQ5ivM9kypJ
# EtSYI3Cz1FpZwyYZyjANBgkqhkiG9w0BAQEFAASCAgAIoMeRsqEihktJsvEZcgvW
# iZ3rHiWgRMMCEtsk7DiFSTiL4r9S6cZWKrF6KnuOltJjFIz71X2h4wgGvjxLx7xw
# Ic9JLyF1WHa5AxQoYySgcyObKeZtdxXVBTafqkGZ61mt/UONWA9TzPZDB1Ese3io
# cOVIduzm+yT+AO55CvLKjaKLJxNfUm0oVzhO90UvRLCjvA/e+7GG/0thdSS55N96
# 3RpOxJm55MnbDKUx13owevz9BcilI0IqnmQm8nrBWw9NZsUC9saAXcs/0Pjqba5u
# JgbX9DAwHUS3shvm1kn5407TBWdcuPP6f9QPEBVoHWJ2RdErrvxIbNyU4pcq4D7j
# 31o47HcCXd0nBJjmojPaDnLoqs56/tpv3YTwjxPGCtatgKJt306R8CkMykKoAL3L
# q3gmfFYv1kBsyBd7GEedjm8X4Ta9vK2q32UXAllqiXNLslTHp52gqJkWwBkw9JPD
# gnjXPKl622vhRBFhJeTrveTG5T7mD2o8U8TLEsxKeL8AfPP+HypdzviRbjkeVOgc
# NBXe0MBr2m2YXy6n2utSN6WgqHqml6cLC2qLJfwZKdxhFW6J2w9tS9IruwRTop2q
# xAw9Vfi1fGljBcCXCoRh19iIWLtcmQQGtTxLHz2rs2dWzNdQWHbYC3Hw9YpOPDHH
# dy+5U61RKzpsLgIfANtEXaGCFzkwghc1BgorBgEEAYI3AwMBMYIXJTCCFyEGCSqG
# SIb3DQEHAqCCFxIwghcOAgEDMQ8wDQYJYIZIAWUDBAIBBQAwdwYLKoZIhvcNAQkQ
# AQSgaARmMGQCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFlAwQCAQUABCAAtePlA7cW
# jZOPKpMHnX6+2whdicfEdIjfjM6WvYHhwgIQBYJ5I5WP/Y58CO5+DxAqkRgPMjAy
# NDExMjYyMDU2NTNaoIITAzCCBrwwggSkoAMCAQICEAuuZrxaun+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
# hvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNDExMjYyMDU2
# NTNaMCsGCyqGSIb3DQEJEAIMMRwwGjAYMBYEFNvThe5i29I+e+T2cUhQhyTVhltF
# MC8GCSqGSIb3DQEJBDEiBCCIjYDGxv8dVp1sTsMCwnwcRkTDIAr+fSdMsU/QVUV6
# kTA3BgsqhkiG9w0BCRACLzEoMCYwJDAiBCB2dp+o8mMvH0MLOiMwrtZWdf7Xc9sF
# 1mW5BZOYQ4+a2zANBgkqhkiG9w0BAQEFAASCAgBUJv0/10IU13nyL/WTeIWv1WPM
# D8rCyQZ/s8oNQeGNdjEw2FJDzaJW4kpaeRgvWnY9xUg18cPwvWgDmDStXd1nD5JO
# Kr6KYCkYsn+ROYSTNu/kOcxPZWHkTmAahQHzC2RFSg9D5E5d1gZiO910kEDfzJMv
# kRj0dz/ED/Ripop2rmqt/m4m+z6X/wSu8X2thXm2LN8eGhfMYanXd8+W6eWovcQ1
# qfUhtQhx1ORMC+gUu4Z575NkkC1LzaiWnWibaUfU/ayQcZrROPcZ/M+iBb+s8p1q
# TsQ8HxULIl2fTHhq0CfDqovOqft2eKtPTrs3IED5BuWDgLvkGtGWRKsiTmRb3dPo
# RefMSIlJpvWMlCRv2p8kpGAutbzHDyiyXYo/Da/XwtfCFAIEyWACx8vqGLJ9p1Np
# Sl2cdK5XePC8uFI+WpSeyX075ss0j9gg7DQlfhAuE3dtyfgEA7ppt0DjKrJf1W1N
# 1vXFOyuVZ2JssP7IPp29Up5GNU5FM/AlGLySYl8CSy148INexVQo/P7JcMLLr9NZ
# Xi+Y4ukmW+OU/rA3WMLI0KzIMSo0xuEX6du4K+dSXOi5Yt8boEF3eGmqdYuRS9lp
# G1u0/b39zH6ETcuy1nO1w5ojuwD1wTzuaYa7c34Gy/Ig6JpcYb4OLf1441ZE5HWP
# JJBHolMfWb1L7nUfOA==
# SIG # End signature block