Modules/CreateReport/CreateReport.psm1

Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath "..\Utility")

function New-Report {
     <#
    .Description
    This function creates the individual HTML/json reports using the TestResults.json.
    Output will be stored as HTML/json files in the InvidualReports folder in the OutPath Folder.
    The report Home page and link tree will be named BaselineReports.html
    .Functionality
    Internal
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("Teams", "EXO", "Defender", "AAD", "PowerPlatform", "SharePoint", IgnoreCase = $false)]
        [string]
        $BaselineName,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("Microsoft Teams", "Exchange Online", "Microsoft 365 Defender", "Azure Active Directory", "Microsoft Power Platform", "SharePoint Online", IgnoreCase = $false)]
        [string]
        $FullName,

        # The location to save the html report in.
        [Parameter(Mandatory=$true)]
        [ValidateScript({Test-Path -PathType Container $_})]
        [ValidateNotNullOrEmpty()]
        [string]
        $IndividualReportPath,

        # The location to save the html report in.
        [Parameter(Mandatory=$true)]
        [ValidateScript({Test-Path -PathType Container $_})]
        [ValidateScript({Test-Path -IsValid $_})]
        [string]
        $OutPath,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $OutProviderFileName,

        [Parameter(Mandatory=$true)]
        [ValidateScript({Test-Path -IsValid $_})]
        [string]
        $OutRegoFileName,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [switch]
        $DarkMode,

        [Parameter(Mandatory=$true)]
        [ValidateNotNull()]
        [object]
        $SecureBaselines
    )

    $ScubaGitHubUrl = "https://github.com/cisagov/ScubaGear"

    $ProductSecureBaseline = $SecureBaselines.$BaselineName

    $FileName = Join-Path -Path $OutPath -ChildPath "$($OutProviderFileName).json" -Resolve
    $SettingsExport =  Get-Utf8NoBom -FilePath $FileName | ConvertFrom-Json

    $FileName = Join-Path -Path $OutPath -ChildPath "$($OutRegoFileName).json" -Resolve
    $TestResults =  Get-Utf8NoBom -FilePath $FileName | ConvertFrom-Json

    $Fragments = @()

    $MetaData += [pscustomobject]@{
        "Tenant Display Name" = $SettingsExport.tenant_details.DisplayName;
        "Report Date" = $SettingsExport.date;
        "Baseline Version" = $SettingsExport.baseline_version;
        "Module Version" = $SettingsExport.module_version
    }

    # Json version of the product-specific report
    $ReportJson = @{
        "MetaData" = $MetaData
        "Results" = @()
    };

    $MetaDataTable = $MetaData | ConvertTo-HTML -Fragment
    $MetaDataTable = $MetaDataTable -replace '^(.*?)<table>','<table id="tenant-data" style = "text-align:center;">'
    $Fragments += $MetaDataTable
    $ReportSummary = @{
        "Warnings" = 0;
        "Failures" = 0;
        "Passes" = 0;
        "Omits" = 0;
        "Manual" = 0;
        "Errors" = 0;
        "Date" = $SettingsExport.date;
    }

    foreach ($BaselineGroup in $ProductSecureBaseline) {
        $Fragment = @()

        foreach ($Control in $BaselineGroup.Controls){

            $Test = $TestResults | Where-Object -Property PolicyId -eq $Control.Id

            if ($null -ne $Test){
                # Check if the config file indicates the control should be omitted
                $Config = $SettingsExport.scuba_config
                $Omit = Get-OmissionState $Config $Control.Id
                if ($Omit) {
                    $ReportSummary.Omits += 1
                    $OmitRationale = $Config.OmitPolicy.$($Control.Id).Rationale
                    if ([string]::IsNullOrEmpty($OmitRationale)) {
                        Write-Warning "Config file indicates omitting $($Control.Id), but no rationale provided."
                        $OmitRationale = "Rationale not provided."
                    }
                    else {
                        $OmitRationale = "`"$($OmitRationale)`""
                    }
                    $Fragment += [pscustomobject]@{
                        "Control ID"=$Control.Id
                        "Requirement"=$Control.Value
                        "Result"= "Omitted"
                        "Criticality"= $Test.Criticality
                        "Details"= "Test omitted by user. $($OmitRationale)"
                    }
                    continue
                }

                $MissingCommands = $Test.Commandlet | Where-Object {$SettingsExport."$($BaselineName)_successful_commands" -notcontains $_}

                if ($MissingCommands.Count -gt 0) {
                    $Result = "Error"
                    $ReportSummary.Errors += 1
                    $MissingString = $MissingCommands -Join ", "
                    $Test.ReportDetails = "This test depends on the following command(s) which did not execute successfully: $($MissingString). See terminal output for more details."
                }
                elseif ($Test.RequirementMet) {
                    $Result = "Pass"
                    $ReportSummary.Passes += 1
                }
                elseif ($Test.Criticality -eq "Should") {
                    $Result = "Warning"
                    $ReportSummary.Warnings += 1
                }
                elseif ($Test.Criticality.EndsWith('3rd Party') -or $test.Criticality.EndsWith('Not-Implemented')) {
                    $Result = "N/A"
                    $ReportSummary.Manual += 1
                }
                else {
                    $Result = "Fail"
                    $ReportSummary.Failures += 1
                }

                $Fragment += [pscustomobject]@{
                    "Control ID"=$Control.Id
                    "Requirement"=$Control.Value
                    "Result"= if ($Control.Deleted) {
                        "-"
                    }
                    elseif ($Control.MalformedDescription) {
                        $ReportSummary.Errors += 1
                        "Error"
                    }
                    else {
                        $Result
                    }
                    "Criticality"=if ($Control.Deleted -or $Control.MalformedDescription) {"-"} else {$Test.Criticality}
                    "Details"=if ($Control.Deleted) {
                        "-"
                    }
                    elseif ($Control.MalformedDescription){
                        "Report issue on <a href=`"$ScubaGitHubUrl/issues`" target=`"_blank`">GitHub</a>"
                    }
                    else {
                        $Test.ReportDetails
                    }
                }
            }
            else {
                $ReportSummary.Errors += 1
                $Fragment += [pscustomobject]@{
                    "Control ID"=$Control.Id
                    "Requirement"=$Control.Value
                    "Result"= "Error - Test results missing"
                    "Criticality"= "-"
                    "Details"= "Report issue on <a href=`"$ScubaGitHubUrl/issues`" target=`"_blank`">GitHub</a>"
                }
                Write-Warning -Message "WARNING: No test results found for Control Id $($Control.Id)"
            }
        }

        # Build the markdown links for each policy table, append as a child inside header tags
        # Example: "AAD-1 Legacy Authentication"
        $Number = $BaselineName.ToUpper() + '-' + $BaselineGroup.GroupNumber
        $Name = $BaselineGroup.GroupName
        $GroupAnchor = New-MarkdownAnchor -GroupNumber $BaselineGroup.GroupNumber -GroupName $BaselineGroup.GroupName
        $GroupReferenceURL = "$($ScubaGitHubUrl)/blob/v$($SettingsExport.module_version)/PowerShell/ScubaGear/baselines/$($BaselineName.ToLower()).md$GroupAnchor"
        $MarkdownLink = "<a class='control_group' href=`"$($GroupReferenceURL)`" target=`"_blank`">$Name</a>"
        $Fragments += $Fragment | ConvertTo-Html -PreContent "<h2>$Number $MarkdownLink</h2>" -Fragment

        # Package Assessment Report into Report JSON by Policy Group
        $ReportJson.Results += [pscustomobject]@{
            GroupName = $BaselineGroup.GroupName;
            GroupNumber = $BaselineGroup.GroupNumber;
            GroupReferenceURL = $GroupReferenceURL;
            Controls = $Fragment;
        }

        # Regex will filter out any <table> tags without an id attribute (replace new fragments only, not <table> tags which have already been modified)
        $Fragments = $Fragments -replace ".*(<table(?![^>]+id)*>)", "<table class='policy-data' id='$Number'>"
    }

    # Craft the json report
    $ReportJson.ReportSummary = $ReportSummary
    $JsonFileName = Join-Path -Path $IndividualReportPath -ChildPath "$($BaselineName)Report.json"
    $ReportJson = ConvertTo-Json @($ReportJson) -Depth 5

    # ConvertTo-Json for some reason converts the <, >, and ' characters into unicode escape sequences.
    # Convert those back to ASCII.
    $ReportJson = $ReportJson.replace("\u003c", "<")
    $ReportJson = $ReportJson.replace("\u003e", ">")
    $ReportJson = $ReportJson.replace("\u0027", "'")
    $ReportJson | Out-File $JsonFileName

    # Finish building the html report
    $Title = "$($FullName) Baseline Report"
    $AADWarning = "The ScubaGear configuration file provides the capability to exclude specific users or groups from some of the Entra ID policy checks.
    Exclusions must only be used if they are approved within an organization's security risk acceptance process.
    See <a href=`"$($ScubaGitHubUrl)/blob/v$($SettingsExport.module_version)/docs/configuration/configuration.md#entra-id-configuration`" target=`"_blank`">this section in the product documentation</a>
    for a list of the policies that accept exclusions and the instructions for setting up exclusions in the configuration file.
    <i>Exclusions can introduce grave risks to your system and must be managed carefully.</i>"

    $NoWarning = "<br/>"
    Add-Type -AssemblyName System.Web

    $ReporterPath = $PSScriptRoot
    $ReportHTMLPath = Join-Path -Path $ReporterPath -ChildPath "IndividualReport"
    $ReportHTML = (Get-Content $(Join-Path -Path $ReportHTMLPath -ChildPath "IndividualReport.html")) -Join "`n"
    $ReportHTML = $ReportHTML.Replace("{TITLE}", $Title)
    $BaselineURL = "<a href=`"$($ScubaGitHubUrl)/blob/v$($SettingsExport.module_version)/PowerShell/ScubaGear/baselines/$($BaselineName.ToLower()).md`" target=`"_blank`"><h3 style=`"width: 100px;`">Baseline Documents</h3></a>"
    $ReportHTML = $ReportHTML.Replace("{BASELINE_URL}", $BaselineURL)

    # Handle AAD-specific reporting
    if ($BaselineName -eq "aad") {

        # Load the CSV file
        $csvPath = Join-Path -Path $PSScriptRoot -ChildPath "MicrosoftLicenseToProductNameMappings.csv"
        $csvData = Import-Csv -Path $csvPath

        $LicenseInfoArray = $SettingsExport.license_information | ForEach-Object {

            $SkuID = $_.SkuId
            # Find the corresponding product name
            $matchingRow = $csvData | Where-Object { $_.GUID -eq $SkuID } | Select-Object -First 1
            $productName = "Unknown SKU Name"
            if ($matchingRow) {
                $productName = $matchingRow.'Product_Display_Name'
            }
            # Create a custom object with relevant properties
            [pscustomobject]@{
                "Product Name" = $productName
                "License SKU Identifier" = $_.SkuPartNumber
                "Licenses in Use" = $_.ConsumedUnits
                "Total Licenses" = $_.PrepaidUnits.Enabled
            }
        }
        # Convert the custom objects to an HTML table
        $LicenseTable = $LicenseInfoArray | ConvertTo-Html -As Table -Fragment
        $LicenseTable = $LicenseTable -replace '^(.*?)<table>','<table id="license-info" style = "text-align:center;">'

        # Create a section header for the licensing information
        $LicensingHTML = "<h2>Tenant Licensing Information</h2>" + $LicenseTable

        if ($null -ne $SettingsExport -and $null -ne $SettingsExport.privileged_service_principals) {

            # Create a section for privileged service principals
            $privilegedServicePrincipalsTable = $SettingsExport.privileged_service_principals.psobject.properties | ForEach-Object {
                $principal = $_.Value
                [pscustomobject]@{
                    "Display Name" = $principal.DisplayName
                    "Service Principal ID" = $principal.ServicePrincipalId
                    "Roles" = ($principal.roles -join ", ")
                    "App ID" = $principal.AppId

                }
            } | ConvertTo-Html -Fragment

            $privilegedServicePrincipalsTable = $privilegedServicePrincipalsTable -replace '^(.*?)<table>', '<table id="privileged-service-principals" style="text-align:center;">'

            # Create a section header for the service principal information
            $privilegedServicePrincipalsTableHTML = "<h2>Privileged Service Principal Table</h2>" + $privilegedServicePrincipalsTable
            $ReportHTML = $ReportHTML.Replace("{SERVICE_PRINCIPAL}", $privilegedServicePrincipalsTableHTML)

        }
        else{
            $ReportHTML = $ReportHTML.Replace("{SERVICE_PRINCIPAL}", "")

        }
        $ReportHTML = $ReportHTML.Replace("{AADWARNING}", $AADWarning)
        $ReportHTML = $ReportHTML.Replace("{LICENSING_INFO}", $LicensingHTML)
        $CapJson = ConvertTo-Json $SettingsExport.cap_table_data
    }
    else {
        $ReportHTML = $ReportHTML.Replace("{AADWARNING}", $NoWarning)
        $ReportHTML = $ReportHTML.Replace("{LICENSING_INFO}", "")
        $ReportHTML = $ReportHTML.Replace("{SERVICE_PRINCIPAL}", "")
        $CapJson = "null"
    }

    $CssPath = Join-Path -Path $ReporterPath -ChildPath "styles"
    $MainCSS = (Get-Content $(Join-Path -Path $CssPath -ChildPath "main.css")) -Join "`n"
    $ReportHTML = $ReportHTML.Replace("{MAIN_CSS}", "<style>
        $($MainCSS)
    </style>"
)

    $ScriptsPath = Join-Path -Path $ReporterPath -ChildPath "scripts"
    $MainJS = (Get-Content $(Join-Path -Path $ScriptsPath -ChildPath "main.js")) -Join "`n"
    $MainJS = "const caps = $($CapJson);`n$($MainJS)"
    $UtilsJS = (Get-Content $(Join-Path -Path $ScriptsPath -ChildPath "utils.js")) -Join "`n"
    $MainJS = "$($MainJS)`n$($UtilsJS)"
    $ReportHTML = $ReportHTML.Replace("{MAIN_JS}", "<script>
        let darkMode = $($DarkMode.ToString().ToLower());
        $($MainJS)
    </script>"
)

    $ReportHTML = $ReportHTML.Replace("{TABLES}", $Fragments)
    $FileName = Join-Path -Path $IndividualReportPath -ChildPath "$($BaselineName)Report.html"
    [System.Web.HttpUtility]::HtmlDecode($ReportHTML) | Out-File $FileName

    $ReportSummary
}

function Get-OmissionState {
    <#
    .Description
    Determine if the supplied control was marked for omission in the config file.
    .Functionality
    Internal
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [PSCustomObject]
        $Config,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ControlId
    )
    $Omit = $false
    if ($Config.psobject.properties.name -Contains "OmitPolicy") {
        if ($Config.OmitPolicy.psobject.properties.name -Contains $ControlId) {
            # The config indicates the control should be omitted
            if ($Config.OmitPolicy.$($ControlId).psobject.properties.name -Contains "Expiration") {
                # An expiration date for the omission expiration was provided. Evaluate the date
                # to see if the control should still be omitted.
                if ($Config.OmitPolicy.$($ControlId).Expiration -eq "") {
                    # If the Expiration date is an empty string, omit the policy
                    $Omit = $true
                }
                else {
                    # An expiration date was provided and it's not an empty string
                    $Now = Get-Date
                    $ExpirationString = $Config.OmitPolicy.$($ControlId).Expiration
                    try {
                        $ExpirationDate = Get-Date -Date $ExpirationString
                        if ($ExpirationDate -lt $Now) {
                            # The expiration date is passed, don't omit the policy
                            $Warning = "Config file indicates omitting $($ControlId), but the provided "
                            $Warning += "expiration date, $ExpirationString, has passed. Control will "
                            $Warning += "not be omitted."
                            Write-Warning $Warning
                        }
                        else {
                            # The expiration date is in the future, omit the policy
                            $Omit = $true
                        }
                    }
                    catch {
                        # Malformed date, don't omit the policy
                        $Warning = "Config file indicates omitting $($ControlId), but the provided "
                        $Warning += "expiration date, $ExpirationString, is malformed. The expected "
                        $Warning += "format is yyyy-mm-dd. Control will not be omitted."
                        Write-Warning $Warning
                    }
                }
            }
            else {
                # The expiration date was not provided, omit the policy
                $Omit = $true
            }
        }
    }
    $Omit
}

function Import-SecureBaseline{
    <#
    .Description
    This function parses the secure baseline via each product markdown document to align policy with the
    software baseline.
    .Functionality
    Internal
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("teams", "exo", "defender", "aad", "powerplatform", "sharepoint", 'powerbi', IgnoreCase = $false)]
        [string[]]
        $ProductNames,
        [Parameter(Mandatory = $false)]
        [ValidateScript({Test-Path -PathType Container $_})]
        [string]
        $BaselinePath = (Join-Path -Path $PSScriptRoot -ChildPath "..\..\baselines\")
    )
    $Output = @{}

    foreach ($Product in $ProductNames) {
        try {
            Write-Debug "Processing secure baseline markdown for $Product"
            $Output[$Product] = @()
            $ProductPath = Join-Path -Path $BaselinePath -ChildPath "$Product.md"
            $MdLines = Get-Content -Path $ProductPath

            # Select-String line numbers aren't 0-indexed, hence the "-1" on the next line
            $LineNumbers = Select-String "^## [0-9]+\." $ProductPath | ForEach-Object {$_."LineNumber"-1}
            $Groups = $LineNumbers | ForEach-Object {$MdLines[$_]}
            Write-Debug "Found $($Groups.Count) groups"

            foreach ($GroupName in $Groups) {
                $Group = @{}
                $Group.GroupNumber = $GroupName.Split(".")[0].SubString(3) # 3 to remove the "## "
                $Group.GroupName = $GroupName.Split(".")[1].Trim() # 1 to remove the leading space
                $Group.Controls = @()

                $IdRegex =  "#### MS\.[$($Product.ToUpper())]+\.$($Group.GroupNumber)\.\d+v\d+\s*$"
                # Select-String line numbers aren't 0-indexed, hence the "-1" on the next line
                $LineNumbers = Select-String $IdRegex $ProductPath | ForEach-Object {$_."LineNumber"-1}

                # Iterate over matched policy ids found
                foreach ($LineNumber in $LineNumbers) {
                    $Value = [System.Net.WebUtility]::HtmlEncode($Value)
                    $Id = [string]$MdLines[$LineNumber].Substring(5)

                    if ($Id.EndsWith("X")){
                        $Deleted = $true
                        $Id = $Id -Replace ".$"
                        $Value = "[DELETED] " + $Value
                    }
                    else {
                        $Deleted = $false
                    }

                    # This assumes that the value is on the immediate next line after the ID and ends in a period.
                    $LineAdvance = 1;
                    $MaxLineSearch = 20;
                    $Value = ([string]$MdLines[$LineNumber+$LineAdvance]).Trim()
                    $IsMalformedDescription = $false
                    $IsList = $false

                    try {
                        if ([string]::IsNullOrWhiteSpace($Value)){
                            $IsMalformedDescription = $true
                            $Value = "Error - The baseline policy text is malformed. Description should start immediately after Policy Id."
                            Write-Error "Expected description for $Id to start on line $($LineNumber+$LineAdvance)"
                        }

                        # Processing multiline description.
                        # TODO: Improve processing GitHub issue #526
                        while ($Value.Substring($Value.Length-1,1) -ne "."){
                            $LineAdvance++

                            if ($Value -match [regex]::Escape("<!--")){
                                # Reached Criticality comment so policy description is complete.
                                break
                            }

                            # Policy description contains a list assuming list is denoted by a colon character.
                            if ($Value[-1] -eq ":") {
                                $isList = $true
                            }

                            if (-not [string]::IsNullOrWhiteSpace([string]$MdLines[$LineNumber+$LineAdvance])) {
                                # List case, use newline character between value text
                                if ($isList) {
                                    $Value += "`n" + ([string]$MdLines[$LineNumber+$LineAdvance]).Trim()
                                }
                                else { # Value ending with newline char, use whitespace character between value text
                                    $Value += " " + ([string]$MdLines[$LineNumber+$LineAdvance]).Trim()
                                }
                            }

                            if ($LineAdvance -gt $MaxLineSearch){
                                Write-Warning "Expected description for $id to end with period and be less than $MaxLineSearch lines"
                                break
                            }
                        }

                        # Description italics substitution
                        $Value = Resolve-HTMLMarkdown -OriginalString $Value -HTMLReplace "italic"

                        # Description bold substitution
                        $Value = Resolve-HTMLMarkdown -OriginalString $Value -HTMLReplace "bold"

                        $Group.Controls += @{"Id"=$Id; "Value"=$Value; "Deleted"=$Deleted; MalformedDescription=$IsMalformedDescription}
                    }
                    catch {
                        Write-Error "Error parsing for policies in Group $($Group.GroupNumber). $($Group.GroupName)"
                    }
                }

                $Output[$Product] += $Group
            }
        }
        catch {
            Write-Error -RecommendedAction "Check validity of $Product secure baseline markdown at $ProductPath" `
                -Message "Failed to parse $ProductName secure baseline markdown."
        }
    }

    $Output
}

function New-MarkdownAnchor{
    param (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $GroupNumber,
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $GroupName
    )
    [Int32]$OutNumber = $null

    if ($true -eq [Int32]::TryParse($GroupNumber, [ref]$OutNumber)){
        $MangledName = $GroupName.ToLower().Trim().Replace(' ', '-')
        return "#$($GroupNumber.Trim())-$MangledName"
    }
    else {
        $InvalidGroupNumber = New-Object System.ArgumentException "$GroupNumber is not valid"
        throw $InvalidGroupNumber
    }
}

function Resolve-HTMLMarkdown{
    param (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $OriginalString,
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $HTMLReplace
    )

    # Replace markdown with italics substitution
    if ($HTMLReplace.ToLower() -match "italic") {
        $ResolvedString = $OriginalString -replace '(_)([^\v][^_]*[^\v])?(_)', '<i>${2}</i>'
        return $ResolvedString
    } elseif($HTMLReplace.ToLower() -match "bold") {
        $ResolvedString = $OriginalString -replace '(\*\*)(.*?)(\*\*)', '<b>${2}</b>'
        return $ResolvedString
    } else {
        $InvalidHTMLReplace = New-Object System.ArgumentException "$HTMLReplace is not valid"
        throw $InvalidHTMLReplace
        return $OriginalString
    }
}

Export-ModuleMember -Function @(
    'New-Report',
    'Import-SecureBaseline'
)

# SIG # Begin signature block
# MIIuugYJKoZIhvcNAQcCoIIuqzCCLqcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAYsZGdGZYXmRXK
# vW2eESA6YB7p+krk3+FNtazE+tkCNKCCE6MwggWQMIIDeKADAgECAhAFmxtXno4h
# 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+cvb0MjjGCGm0wghppAgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNV
# BAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0
# IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQD9bmIMUq+I6M
# gaQf3mTiLjANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgACh
# AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM
# BgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCAySyH7tg/qNPLxSByg1VbMeMLr
# wfI1HhYamXp8BRYI7jANBgkqhkiG9w0BAQEFAASCAgALPS1nDQ7h0fxM9zlDC5Gt
# t5VSXF38EBUu/4kbhIXVwCanxoQavO31rPtSj2m7DA4shBv9y6fN8/ebGDE0byhC
# bKKSifxOTvR8ylJh/fZxAGKX+ncd2XHZb+Y3aMw/fK/8qpVcDG7biTZjVe2BkZ2c
# p3ZLpZ+aHnJQHxZNs68Aggog+o2HtWbi76kwHw/vRtWHoNKghFT3aUy+/01p+0Eq
# 7ePpCH/ZKbyvheGaVi6x97bVTR9E95usebSfr0538qzMkdoJikHqHA7VQIA8w2cA
# N2z/jenkAR8oSNppZNGC0w53JXBf4r6Xgxjw2uy9IBJ3m1uN8E9CaGBnSpsYJCNd
# hTANm5/+e+MD/6MGya37W6MCxEvDuuKg4z2O8khjQDmF9Dh0nOmK9R+eBeHJJxsG
# yMO+Yw1hcy3vQyUJuqO8fFjOlappYF9SIfffVdRO15t/rcNkY8Rb8db8UzQBvQTK
# quIBNV6eNt3ClGFYDc97GwK8DV8rC/6CoVDaxE4UE2oqOwhoqESeN6hvYs1Bh6j5
# D/sAcn0aVo0YyLsKjYT3MQgOLx7k03rKf465dhtuXZf4i0jg4+MiDe1uH6Idxezc
# dcdhUID2rz90APY5ouUlt7tKqKW52JHbU2ewbbY4IPTBUChnyvJEBIm7wQkaTgB6
# 3VYsmGRX023ZAOY+Bp+sH6GCFzowghc2BgorBgEEAYI3AwMBMYIXJjCCFyIGCSqG
# SIb3DQEHAqCCFxMwghcPAgEDMQ8wDQYJYIZIAWUDBAIBBQAweAYLKoZIhvcNAQkQ
# AQSgaQRnMGUCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFlAwQCAQUABCA4BFZ7L35A
# maVa5Ij+sZCm69qn+hpMQPbpZbqmzVe2oQIRAO5SyM9Rbg+QDBdpxJEEZvoYDzIw
# MjUwMjEwMjA1MTExWqCCEwMwgga8MIIEpKADAgECAhALrma8Wrp/lYfG+ekE4zME
# MA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2Vy
# dCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNI
# QTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjQwOTI2MDAwMDAwWhcNMzUxMTI1MjM1
# OTU5WjBCMQswCQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNlcnQxIDAeBgNVBAMT
# F0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDI0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
# MIICCgKCAgEAvmpzn/aVIauWMLpbbeZZo7Xo/ZEfGMSIO2qZ46XB/QowIEMSvgjE
# dEZ3v4vrrTHleW1JWGErrjOL0J4L0HqVR1czSzvUQ5xF7z4IQmn7dHY7yijvoQ7u
# jm0u6yXF2v1CrzZopykD07/9fpAT4BxpT9vJoJqAsP8YuhRvflJ9YeHjes4fduks
# THulntq9WelRWY++TFPxzZrbILRYynyEy7rS1lHQKFpXvo2GePfsMRhNf1F41nyE
# g5h7iOXv+vjX0K8RhUisfqw3TTLHj1uhS66YX2LZPxS4oaf33rp9HlfqSBePejlY
# eEdU740GKQM7SaVSH3TbBL8R6HwX9QVpGnXPlKdE4fBIn5BBFnV+KwPxRNUNK6lY
# k2y1WSKour4hJN0SMkoaNV8hyyADiX1xuTxKaXN12HgR+8WulU2d6zhzXomJ2Ple
# I9V2yfmfXSPGYanGgxzqI+ShoOGLomMd3mJt92nm7Mheng/TBeSA2z4I78JpwGpT
# RHiT7yHqBiV2ngUIyCtd0pZ8zg3S7bk4QC4RrcnKJ3FbjyPAGogmoiZ33c1HG93V
# p6lJ415ERcC7bFQMRbxqrMVANiav1k425zYyFMyLNyE1QulQSgDpW9rtvVcIH7Wv
# G9sqYup9j8z9J1XqbBZPJ5XLln8mS8wWmdDLnBHXgYly/p1DhoQo5fkCAwEAAaOC
# AYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM
# MAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATAf
# BgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAdBgNVHQ4EFgQUn1csA3cO
# KBWQZqVjXu5Pkh92oFswWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2NybDMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFt
# cGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUHMAGGGGh0dHA6
# Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZMaHR0cDovL2NhY2VydHMu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVT
# dGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAPa0eH3aZW+M4hBJH2UOR
# 9hHbm04IHdEoT8/T3HuBSyZeq3jSi5GXeWP7xCKhVireKCnCs+8GZl2uVYFvQe+p
# PTScVJeCZSsMo1JCoZN2mMew/L4tpqVNbSpWO9QGFwfMEy60HofN6V51sMLMXNTL
# fhVqs+e8haupWiArSozyAmGH/6oMQAh078qRh6wvJNU6gnh5OruCP1QUAvVSu4kq
# VOcJVozZR5RRb/zPd++PGE3qF1P3xWvYViUJLsxtvge/mzA75oBfFZSbdakHJe2B
# VDGIGVNVjOp8sNt70+kEoMF+T6tptMUNlehSR7vM+C13v9+9ZOUKzfRUAYSyyEmY
# tsnpltD/GWX8eM70ls1V6QG/ZOB6b6Yum1HvIiulqJ1Elesj5TMHq8CWT/xrW7tw
# ipXTJ5/i5pkU5E16RSBAdOp12aw8IQhhA/vEbFkEiF2abhuFixUDobZaA0VhqAsM
# HOmaT3XThZDNi5U2zHKhUs5uHHdG6BoQau75KiNbh0c+hatSF+02kULkftARjsyE
# pHKsF7u5zKRbt5oK5YGwFvgc4pEVUNytmB3BpIiowOIIuDgP5M9WArHYSAR16gc0
# dP2XdkMEP5eBsX7bf/MGN4K3HP50v/01ZHo/Z5lGLvNwQ7XHBx1yomzLP8lx4Q1z
# ZKDyHcp4VQJLu2kWTsKsOqQwggauMIIElqADAgECAhAHNje3JFR82Ees/ShmKl5b
# MA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD
# ZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0zNzAzMjIyMzU5
# NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkG
# A1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3Rh
# bXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGhjUGSbPB
# PXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGhRBVCX6SI82j6ffOciQt/
# nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9xBd/qxkrPkLc
# Z47qUT3w1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdGAHvbREGJ3HxqV3rwN3mf
# XazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9zvU5EmfvDqVjbOSmxR3N
# Ng1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKlSNbwsDETqVcplicu9Yem
# j052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae5jtb7IHeIhTZgirHkr+g
# 3uM+onP65x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnzyqqWc0Jon7ZGs506o9UD
# 4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ9FHzNklNiyDS
# LFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/TXkt2ElGTyYwM
# O1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbsq11GdeJgo1gJASgADoRU
# 7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IBXTCCAVkwEgYDVR0TAQH/
# BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2FL3MpdpovdYxqII+eyG8wHwYDVR0j
# BBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1Ud
# JQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0
# cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0
# cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8E
# PDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz
# dGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEw
# DQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGwGC4QTRPPMFPO
# vxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dth/qEICU0MWfNthKWb8RQ
# TGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1DX+1gtqpPkWae
# LJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd6f8oVInw1YpxdmXazPBy
# oyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY+/umnXKvxMfB
# wWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0ISQ+UzTl63f8l
# Y5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr5Dhzq6YBT70/
# O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGYX/sr2H7yRp11LB4nLCbb
# bxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFmut1VwDophrCYoCvtlUG3
# OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/AAvkdgIm2fBl
# dkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMOHds3OBqhK/bt
# 1nz8MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0BAQwF
# ADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
# ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElE
# IFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQswCQYD
# VQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGln
# aWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIi
# MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKn
# JS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/W
# BTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHi
# LQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhm
# V1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHE
# tWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6
# MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mX
# aXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZ
# xd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfh
# vbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvl
# EFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn1
# 5GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
# HQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SSy4Ix
# LVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAkBggr
# BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdo
# dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290
# Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRVHSAA
# MA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyhhyzs
# hV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO0Cre
# +i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo8L8v
# C6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++hUD38
# dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5xaiNr
# Iv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMYIDdjCCA3ICAQEw
# dzBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNV
# BAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1w
# aW5nIENBAhALrma8Wrp/lYfG+ekE4zMEMA0GCWCGSAFlAwQCAQUAoIHRMBoGCSqG
# SIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjUwMjEwMjA1
# MTExWjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBTb04XuYtvSPnvk9nFIUIck1YZb
# RTAvBgkqhkiG9w0BCQQxIgQgIM03GF/KugaYEDMEyHT19ychzflWilOyRIsoy5QK
# 3sowNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQgdnafqPJjLx9DCzojMK7WVnX+13Pb
# BdZluQWTmEOPmtswDQYJKoZIhvcNAQEBBQAEggIAu29BQdSFwdQ1WxJsaXamJzO3
# VdWM/u+2llsgh9tm906HDzLNZeTmaAYmP7fmFi0I9DLRGAsyq2bg8ITATTrAKV9X
# l6w92VJ1PBQZMcZdtz0Z6Boci5RUKQ76XbGX4+ZBrWw7P9diDV554PPj70SDUfqN
# C2m5/Lfxism0WyILgkbK6r/YFVnZMDka90kRzVCFOc0YWntBz36Vz49IJQzuEmcP
# R77u08SQYmavg5Qo5uUFI42vD8fAGXR0Ow8cSE1INApOvyMAN+9yt8eBcb2EXuo4
# He241oLpe5bRFAU0uYjxXNyDqAoVN5UmlBtYc0hkQmiMHl1n/0aS8+CrVzvrPoHE
# kcUNwIYCTfuxP7hPkCBA9ys/HKIXpnsEes2MT41LnRjWph7xnkpJC5fRm83zc0Fw
# LMfVok7KbhrhzShVJORvj6CcO4s5wW+VPDRuToSok970OT/r3BMRdHatNVfWXmqO
# cxD5egO6zV5fnXPKnhdZthpmAjKUN503Z0TK3dnj/KWWDIneFkNM+jDCeCBE3vFE
# PwiKHaEOYBYAe3ART86vCI/CBu6i8kHtUo1VPYsTdtsqL+/brEenr2JVmwkJYV4P
# 7IrOURMY5FmELJAP7Q+CF37LHa5H2BggZ6cE4RgTESrmWsPHjbG1mLW0o5B0njTz
# VIz2y1jsJiW/DKQMgos=
# SIG # End signature block