helpers/reports/Export-DynamicDashboardHtml.ps1

function Export-DynamicDashboardHtml {
    <#
    .SYNOPSIS
        Generates an interactive HTML dashboard from any array of objects.
    .DESCRIPTION
        Takes any array of PSCustomObjects (or hashtables) and produces a self-contained
        HTML report with auto-generated summary cards, a sortable/searchable Bootstrap
        Table, row counter, pagination toggle, and multi-format export (CSV, XLSX, JSON,
        TXT, TSV, SQL, PNG, XLS).
 
        Summary cards are auto-detected from the data:
        - A "Total" card is always generated first.
        - If a -CardField is specified, unique values of that field become clickable
          filter cards.
        - If -CardField is not specified, the function looks for common status-like
          fields (Status, State, PowerState, ProvisioningState, Health, Result) and
          uses the first one found.
        - If no status-like field is found, up to 5 low-cardinality string fields
          (fewer than 10 unique values) are auto-detected and used as card groups.
 
        Column titles are auto-humanised from PascalCase (e.g. "IPAddress" becomes
        "IP Address"). A -StatusField can mark a column for automatic colour-coded
        formatting (green/red/orange dots based on common status keywords).
    .PARAMETER Data
        Array of objects to render. Accepts pipeline input.
    .PARAMETER OutputPath
        File path for the output HTML file. If omitted, defaults to
        $env:TEMP\WhatsUpGoldPS-Report-<datetime>.html.
    .PARAMETER ReportTitle
        Title shown in the report header and browser tab. Defaults to "Dashboard".
    .PARAMETER CardField
        One or more property names to group summary cards by. Each field gets
        its own labelled row of cards. Accepts an array, e.g. -CardField 'role','bestState'.
        If omitted, auto-detection picks common status-like fields.
    .PARAMETER StatusField
        Property name to apply automatic status colour formatting to (green dot
        for running/active/up, red dot for stopped/failed/down, etc.). If omitted,
        auto-detection looks for common status field names.
    .PARAMETER ExportPrefix
        Filename prefix for exported files (e.g. "my_report" produces
        "my_report.csv"). Defaults to "dashboard_export".
    .PARAMETER ThresholdField
        One or more hashtables defining numeric threshold colouring for columns.
        Each hashtable must contain: Field (property name), Warning (number),
        Critical (number). Optionally add Invert=$true when lower values are
        worse (e.g. free disk space).
 
        Normal (default): >= Critical = red, >= Warning = orange, else green.
        Inverted: <= Critical = red, <= Warning = orange, else green.
 
        Example:
          -ThresholdField @{Field='cpuUtil'; Warning=80; Critical=90},
                          @{Field='diskFreePercent'; Warning=20; Critical=10; Invert=$true}
    .PARAMETER TemplatePath
        Path to a custom HTML template. Defaults to Dynamic-Dashboard-Template.html
        in the same directory as this script.
    .PARAMETER Offline
        When specified, rewrites CDN URLs to local file:/// paths pointing to the
        dependency folder (helpers\reports\dependency\). Use this for environments
        without internet access. The dependency files must be pre-downloaded.
    .EXAMPLE
        Get-Process | Select-Object Name, Id, CPU, WorkingSet |
            Export-DynamicDashboardHtml -OutputPath "$env:TEMP\procs.html" -ReportTitle "Processes"
        Start-Process "$env:TEMP\procs.html"
 
        Generates a process dashboard and opens it in the default browser.
    .EXAMPLE
        $data = Get-Content .\servers.json | ConvertFrom-Json
        Export-DynamicDashboardHtml -Data $data -OutputPath "C:\Reports\servers.html" `
            -ReportTitle "Server Inventory" -CardField "Status","Role" -StatusField "Status"
 
        Generates a server inventory dashboard with two card rows: one grouped by Status, one by Role.
    .EXAMPLE
        Import-Csv .\assets.csv |
            Export-DynamicDashboardHtml -OutputPath "$env:TEMP\assets.html" `
                -ReportTitle "Asset Report" -CardField "Location" -ExportPrefix "assets"
 
        Generates a dashboard from CSV data, grouped by Location.
    .OUTPUTS
        System.String The full path of the generated HTML file.
    .NOTES
        Author : jason@wug.ninja
        Version : 1.0.0
        Requires: PowerShell 5.1+
    .LINK
        https://github.com/jayyx2/WhatsUpGoldPS
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [object[]]$Data,

        [string]$OutputPath,

        [string]$ReportTitle = 'Dashboard',

        [string[]]$CardField,

        [string]$StatusField,

        [string]$ExportPrefix = 'dashboard_export',

        [hashtable[]]$ThresholdField,

        [string]$TemplatePath,

        [switch]$Offline
    )

    begin {
        $collected = [System.Collections.Generic.List[object]]::new()
    }

    process {
        foreach ($item in $Data) {
            $collected.Add($item)
        }
    }

    end {
        if ($collected.Count -eq 0) {
            throw "No data provided. Supply at least one object."
        }

        # --- Resolve OutputPath ---
        if (-not $OutputPath) {
            $timestamp = (Get-Date).ToString('yyyyMMdd-HHmmss')
            $OutputPath = Join-Path $env:TEMP "WhatsUpGoldPS-Report-$timestamp.html"
        }

        # --- Resolve template ---
        if (-not $TemplatePath) {
            $TemplatePath = Join-Path $PSScriptRoot 'Dynamic-Dashboard-Template.html'
        }
        if (-not (Test-Path $TemplatePath)) {
            throw "HTML template not found at $TemplatePath"
        }

        $allData = @($collected)

        # --- Flatten nested objects/arrays to readable strings ---
        $flatData = [System.Collections.Generic.List[object]]::new()
        foreach ($row in $allData) {
            $flat = [ordered]@{}
            foreach ($prop in $row.PSObject.Properties) {
                $val = $prop.Value
                if ($null -eq $val) {
                    $flat[$prop.Name] = $null
                }
                elseif ($val -is [System.Collections.IEnumerable] -and $val -isnot [string]) {
                    # Array or collection
                    $items = @($val)
                    if ($items.Count -eq 0) {
                        $flat[$prop.Name] = ''
                    }
                    elseif ($items[0] -is [string] -or $items[0] -is [ValueType]) {
                        # Array of simple values — join with comma
                        $flat[$prop.Name] = ($items | ForEach-Object { "$_" }) -join ', '
                    }
                    else {
                        # Array of objects — pick a display name or flatten each
                        $parts = @()
                        foreach ($obj in $items) {
                            $props = @($obj.PSObject.Properties)
                            # Try common display properties first
                            $displayVal = $null
                            foreach ($dn in @('Name','DisplayName','name','displayName','Title','title','Id','id','Description')) {
                                $found = $props | Where-Object { $_.Name -eq $dn } | Select-Object -First 1
                                if ($found -and $found.Value) {
                                    $displayVal = "$($found.Value)"
                                    break
                                }
                            }
                            if ($displayVal) {
                                $parts += $displayVal
                            }
                            else {
                                # Fallback: key=value pairs for up to 3 properties
                                $kvPairs = @()
                                foreach ($p in ($props | Select-Object -First 3)) {
                                    $pv = $p.Value
                                    if ($pv -is [System.Collections.IEnumerable] -and $pv -isnot [string]) {
                                        $pv = ($pv | ForEach-Object { "$_" }) -join '; '
                                    }
                                    $kvPairs += "$($p.Name)=$pv"
                                }
                                $parts += ($kvPairs -join ', ')
                            }
                        }
                        $flat[$prop.Name] = $parts -join ' | '
                    }
                }
                elseif ($val.PSObject.Properties.Count -gt 0 -and $val -isnot [string] -and $val -isnot [ValueType] -and $val -isnot [datetime]) {
                    # Single nested object — flatten to key=value
                    $kvPairs = @()
                    foreach ($p in ($val.PSObject.Properties | Select-Object -First 5)) {
                        $pv = $p.Value
                        if ($pv -is [System.Collections.IEnumerable] -and $pv -isnot [string]) {
                            $pv = ($pv | ForEach-Object { "$_" }) -join '; '
                        }
                        $kvPairs += "$($p.Name)=$pv"
                    }
                    $flat[$prop.Name] = $kvPairs -join ', '
                }
                else {
                    $flat[$prop.Name] = $val
                }
            }
            $flatData.Add([PSCustomObject]$flat)
        }
        $allData = @($flatData)
        $firstObj = $allData[0]

        # --- Helper: resolve a field name to the actual property name (exact case) ---
        # PowerShell is case-insensitive but JavaScript is not. We must use the
        # real property name so JSON keys match in the browser.
        $propNames = @($firstObj.PSObject.Properties.Name)
        function Resolve-FieldName ([string]$Name) {
            foreach ($p in $propNames) {
                if ($p -ieq $Name) { return $p }
            }
            return $null
        }

        # --- Auto-detect StatusField ---
        $knownStatusFields = @('Status','State','PowerState','ProvisioningState','Health','Result','Availability','bestState')
        if ($StatusField) {
            $resolved = Resolve-FieldName $StatusField
            if ($resolved) { $StatusField = $resolved } else { Write-Warning "StatusField '$StatusField' not found in data. Ignoring."; $StatusField = $null }
        }
        else {
            foreach ($sf in $knownStatusFields) {
                $resolved = Resolve-FieldName $sf
                if ($resolved) {
                    $StatusField = $resolved
                    Write-Verbose "Auto-detected status field: $StatusField"
                    break
                }
            }
        }

        # --- Resolve CardField(s) ---
        $resolvedCardFields = @()
        if ($CardField -and $CardField.Count -gt 0) {
            foreach ($cf in $CardField) {
                $resolved = Resolve-FieldName $cf
                if ($resolved) { $resolvedCardFields += $resolved }
                else { Write-Warning "CardField '$cf' not found in data. Ignoring." }
            }
        }
        if ($resolvedCardFields.Count -eq 0) {
            # Auto-detect: try known status fields first
            foreach ($sf in $knownStatusFields) {
                $resolved = Resolve-FieldName $sf
                if ($resolved) {
                    $resolvedCardFields += $resolved
                    Write-Verbose "Auto-detected card field: $resolved"
                    break
                }
            }
        }
        if ($resolvedCardFields.Count -eq 0) {
            # Fallback: first low-cardinality string column
            foreach ($prop in $firstObj.PSObject.Properties) {
                $sample = @($allData | ForEach-Object { $_.$($prop.Name) } | Where-Object { $_ -ne $null -and $_ -ne '' } | Select-Object -Unique)
                if ($sample.Count -ge 2 -and $sample.Count -le 15) {
                    $avgLen = ($sample | ForEach-Object { "$_".Length } | Measure-Object -Average).Average
                    if ($avgLen -le 30) {
                        $resolvedCardFields += $prop.Name
                        Write-Verbose "Auto-detected card field (low-cardinality): $($prop.Name)"
                        break
                    }
                }
            }
        }

        # --- Build card groups (one group per CardField) ---
        $cardGroups = @()
        foreach ($field in $resolvedCardFields) {
            # Humanise the field name for the group label
            $label = $field -creplace '([a-z])([A-Z])', '$1 $2'
            $label = ($label -creplace '([A-Z]+)([A-Z][a-z])', '$1 $2').Trim()
            $label = $label.Substring(0,1).ToUpper() + $label.Substring(1)

            $uniqueVals = @($allData | ForEach-Object { $_.$field } | Where-Object { $_ -ne $null -and $_ -ne '' } | Sort-Object | Select-Object -Unique)
            $cards = @()
            $cards += @{ label = 'Total'; filterField = '__total__' }
            foreach ($val in $uniqueVals) {
                $cards += @{
                    label        = "$val"
                    filterField  = $field
                    filterValues = @("$val".ToLower())
                }
            }
            $cardGroups += @{ groupLabel = $label; cards = $cards }
        }
        if ($cardGroups.Count -eq 0) {
            # No card fields at all — just show a Total card
            $cardGroups += @{ groupLabel = 'Summary'; cards = @(@{ label = 'Total'; filterField = '__total__' }) }
        }

        $cardGroupsJson = $cardGroups | ConvertTo-Json -Depth 5 -Compress
        if ($cardGroups.Count -eq 1) { $cardGroupsJson = "[$cardGroupsJson]" }

        # --- Resolve ThresholdField definitions ---
        $thresholdDefs = @()
        if ($ThresholdField) {
            foreach ($tf in $ThresholdField) {
                if (-not $tf.Field) { Write-Warning 'ThresholdField entry missing Field key. Skipping.'; continue }
                if ($null -eq $tf.Warning -or $null -eq $tf.Critical) { Write-Warning "ThresholdField '$($tf.Field)' missing Warning or Critical. Skipping."; continue }
                $resolved = Resolve-FieldName $tf.Field
                if (-not $resolved) { Write-Warning "ThresholdField '$($tf.Field)' not found in data. Skipping."; continue }
                $thresholdDefs += @{
                    field    = $resolved
                    warning  = [double]$tf.Warning
                    critical = [double]$tf.Critical
                    invert   = [bool]$tf.Invert
                }
                Write-Verbose "Threshold: $resolved warning=$($tf.Warning) critical=$($tf.Critical) invert=$($tf.Invert)"
            }
        }
        $thresholdDefsJson = $thresholdDefs | ConvertTo-Json -Depth 5 -Compress
        if ($thresholdDefs.Count -le 1) { $thresholdDefsJson = "[$thresholdDefsJson]" }

        # --- Build columns ---
        $columns = @()
        foreach ($prop in $firstObj.PSObject.Properties) {
            # Humanise PascalCase/camelCase: hostName→Host Name, IPAddress→IP Address
            $title = $prop.Name -creplace '([a-z])([A-Z])', '$1 $2'
            $title = ($title -creplace '([A-Z]+)([A-Z][a-z])', '$1 $2').Trim()
            $title = $title.Substring(0,1).ToUpper() + $title.Substring(1)

            $col = @{
                field      = $prop.Name
                title      = $title
                sortable   = $true
                searchable = $true
            }

            if ($StatusField -and $prop.Name -eq $StatusField) {
                $col.formatter = 'formatStatusAuto'
            }

            # Check if this column has a threshold definition
            $matchingThreshold = $thresholdDefs | Where-Object { $_.field -eq $prop.Name } | Select-Object -First 1
            if ($matchingThreshold) {
                $col.formatter = 'formatThreshold'
            }

            $columns += $col
        }

        $columnsJson = $columns | ConvertTo-Json -Depth 5 -Compress
        $dataJson    = $allData  | ConvertTo-Json -Depth 5 -Compress

        # Handle single-item arrays (ConvertTo-Json unwraps single-element arrays)
        if ($columns.Count -eq 1) {
            $columnsJson = "[$columnsJson]"
        }
        if ($allData.Count -eq 1) {
            $dataJson = "[$dataJson]"
        }

        $tableConfig = @"
        columns: $columnsJson,
        data: $dataJson
"@


        # --- Render template ---
        # Use [string].Replace() instead of -replace to avoid regex interpretation
        # of $ characters in JSON data or user-supplied strings.
        $html = Get-Content -Path $TemplatePath -Raw
        $html = $html.Replace('replaceThisHere',              $tableConfig)
        $html = $html.Replace('replaceSummaryCardsHere',      $cardGroupsJson)
        $html = $html.Replace('replaceThresholdDefsHere',     $thresholdDefsJson)
        $html = $html.Replace('replaceExportPrefixHere',      $ExportPrefix)
        $html = $html.Replace('ReplaceYourReportNameHere',    $ReportTitle)
        $html = $html.Replace('ReplaceUpdateTimeHere',        (Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))

        # --- Resolve local dependencies (offline mode) ---
        if ($Offline) {
            $depFolder = Join-Path $PSScriptRoot 'dependency'
            if (Test-Path $depFolder) {
                $depUri = ([System.Uri](Resolve-Path $depFolder).Path).AbsoluteUri
                $cdnMap = @{
                    'https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css'       = "$depUri/bootstrap.min.css"
                    'https://cdn.jsdelivr.net/npm/bootstrap-table/dist/bootstrap-table.min.css' = "$depUri/bootstrap-table.min.css"
                    'https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.min.css' = "$depUri/bootstrap-icons.min.css"
                    'https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js'                  = "$depUri/jquery.min.js"
                    'https://cdn.jsdelivr.net/npm/@popperjs/core/dist/umd/popper.min.js'      = "$depUri/popper.min.js"
                    'https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.min.js'         = "$depUri/bootstrap.min.js"
                    'https://cdn.jsdelivr.net/npm/bootstrap-table/dist/bootstrap-table.min.js' = "$depUri/bootstrap-table.min.js"
                    'https://cdn.jsdelivr.net/npm/file-saver/dist/FileSaver.min.js'           = "$depUri/FileSaver.min.js"
                    'https://cdn.jsdelivr.net/npm/xlsx/dist/xlsx.full.min.js'                 = "$depUri/xlsx.full.min.js"
                    'https://cdn.jsdelivr.net/npm/html2canvas/dist/html2canvas.min.js'        = "$depUri/html2canvas.min.js"
                }
                foreach ($cdn in $cdnMap.GetEnumerator()) {
                    $html = $html.Replace($cdn.Key, $cdn.Value)
                }
                Write-Verbose "Using local dependencies from $depFolder"
            }
            else {
                Write-Warning "Offline mode requested but dependency folder not found at $depFolder. Using CDN URLs."
            }
        }

        Set-Content -Path $OutputPath -Value $html -Encoding UTF8
        Write-Verbose "Dashboard written to $OutputPath"
        return $OutputPath
    }
}

# SIG # Begin signature block
# MIIr+wYJKoZIhvcNAQcCoIIr7DCCK+gCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBPp+B95MQppI5a
# Vp2Aan4MVRVjqFfI7DxYseuSHeZ4nqCCJQ0wggVvMIIEV6ADAgECAhBI/JO0YFWU
# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM
# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy
# dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG
# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv
# IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s
# hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD
# J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7
# P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme
# me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz
# T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q
# RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz
# mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc
# QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T
# OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/
# AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID
# AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD
# VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE
# VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v
# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE
# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI
# hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF
# OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC
# J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ
# pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl
# d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH
# +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggWNMIIEdaADAgECAhAOmxiO
# +dAt5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYD
# VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAi
# BgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAw
# MDBaFw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp
# Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERp
# Z2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsb
# hA3EMB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iT
# cMKyunWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGb
# NOsFxl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclP
# XuU15zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCr
# VYJBMtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFP
# ObURWBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTv
# kpI6nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWM
# cCxBYKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls
# 5Q5SUUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBR
# a2+xq4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6
# MIIBNjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qY
# rhwPTzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8E
# BAMCAYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k
# aWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDig
# NoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v
# dENBLmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCg
# v0NcVec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQT
# SnovLbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh
# 65ZyoUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSw
# uKFWjuyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAO
# QGPFmCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjD
# TZ9ztwGpn1eqXijiuZQwggYaMIIEAqADAgECAhBiHW0MUgGeO5B5FSCJIRwKMA0G
# CSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExp
# bWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBSb290
# IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5NTlaMFQxCzAJBgNVBAYT
# AkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28g
# UHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0GCSqGSIb3DQEBAQUAA4IB
# jwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjIztNsfvxYB5UXeWUzCxEe
# AEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NVDgFigOMYzB2OKhdqfWGV
# oYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/36F09fy1tsB8je/RV0mIk
# 8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05ZwmRmTnAO5/arnY83jeNzh
# P06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm+qxp4VqpB3MV/h53yl41
# aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUedyz8rNyfQJy/aOs5b4s+
# ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz44MPZ1f9+YEQIQty/NQd/
# 2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBMdlyh2n5HirY4jKnFH/9g
# Rvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQYMBaAFDLrkpr/NZZILyhA
# QnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritUpimqF6TNDDAOBgNVHQ8B
# Af8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNVHSUEDDAKBggrBgEFBQcD
# AzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsGA1UdHwREMEIwQKA+oDyG
# Omh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5n
# Um9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsGAQUFBzAChjpodHRwOi8v
# Y3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ1Jvb3RSNDYu
# cDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG
# 9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURhw1aVcdGRP4Wh60BAscjW
# 4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0ZdOaWTsyNyBBsMLHqafvIh
# rCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajjcw5+w/KeFvPYfLF/ldYp
# mlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNcWbWDRF/3sBp6fWXhz7Dc
# ML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalOhOfCipnx8CaLZeVme5yE
# Lg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJszkyeiaerlphwoKx1uHRz
# NyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z76mKnzAfZxCl/3dq3dUNw
# 4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5JKdGvspbOrTfOXyXvmPL6
# E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHHj95Ejza63zdrEcxWLDX6
# xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2Bev6SivBBOHY+uqiirZt
# g0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/L9Uo2bC5a4CH2RwwggY+
# MIIEpqADAgECAhAHnODk0RR/hc05c892LTfrMA0GCSqGSIb3DQEBDAUAMFQxCzAJ
# BgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNl
# Y3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwHhcNMjYwMjA5MDAwMDAw
# WhcNMjkwNDIxMjM1OTU5WjBVMQswCQYDVQQGEwJVUzEUMBIGA1UECAwLQ29ubmVj
# dGljdXQxFzAVBgNVBAoMDkphc29uIEFsYmVyaW5vMRcwFQYDVQQDDA5KYXNvbiBB
# bGJlcmlubzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPN6aN4B1yYW
# kI5b5TBj3I0VV/peETrHb6EY4BHGxt8Ap+eT+WpEpJyEtRYPxEmNJL3A38Bkg7mw
# zPE3/1NK570ZBCuBjSAn4mSDIgIuXZnvyBO9W1OQs5d67MlJLUAEufl18tOr3ST1
# DeO9gSjQSAE5Nql0QDxPnm93OZBon+Fz3CmE+z3MwAe2h4KdtRAnCqwM+/V7iBdb
# w+JOxolpx+7RVjGyProTENIG3pe/hKvPb501lf8uBAADLdjZr5ip8vIWbf857Yw1
# Bu10nVI7HW3eE8Cl5//d1ribHlzTzQLfttW+k+DaFsKZBBL56l4YAlIVRsrOiE1k
# dHYYx6IGrEA809R7+TZA9DzGqyFiv9qmJAbL4fDwetDeyIq+Oztz1LvEdy8Rcd0J
# BY+J4S0eDEFIA3X0N8VcLeAwabKb9AjulKXwUeqCJLvN79CJ90UTZb2+I+tamj0d
# n+IKMEsJ4v4Ggx72sxFr9+6XziodtTg5Luf2xd6+PhhamOxF2px9LObhBLLEMyRs
# CHZIzVZOFKu9BpHQH7ufGB+Sa80Tli0/6LEyn9+bMYWi2ttn6lLOPThXMiQaooRU
# q6q2u3+F4SaPlxVFLI7OJVMhar6nW6joBvELTJPmANSMjDSRFDfHRCdGbZsL/keE
# LJNy+jZctF6VvxQEjFM8/bazu6qYhrA7AgMBAAGjggGJMIIBhTAfBgNVHSMEGDAW
# gBQPKssghyi47G9IritUpimqF6TNDDAdBgNVHQ4EFgQU6YF0o0D5AVhKHbVocr8G
# aSIBibAwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYI
# KwYBBQUHAwMwSgYDVR0gBEMwQTA1BgwrBgEEAbIxAQIBAwIwJTAjBggrBgEFBQcC
# ARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQBMEkGA1UdHwRCMEAw
# PqA8oDqGOGh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVT
# aWduaW5nQ0FSMzYuY3JsMHkGCCsGAQUFBwEBBG0wazBEBggrBgEFBQcwAoY4aHR0
# cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIz
# Ni5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqG
# SIb3DQEBDAUAA4IBgQAEIsm4xnOd/tZMVrKwi3doAXvCwOA/RYQnFJD7R/bSQRu3
# wXEK4o9SIefye18B/q4fhBkhNAJuEvTQAGfqbbpxow03J5PrDTp1WPCWbXKX8Oz9
# vGWJFyJxRGftkdzZ57JE00synEMS8XCwLO9P32MyR9Z9URrpiLPJ9rQjfHMb1BUd
# vaNayomm7aWLAnD+X7jm6o8sNT5An1cwEAob7obWDM6sX93wphwJNBJAstH9Ozs6
# LwISOX6sKS7CKm9N3Kp8hOUue0ZHAtZdFl6o5u12wy+zzieGEI50fKnN77FfNKFO
# WKlS6OJwlArcbFegB5K89LcE5iNSmaM3VMB2ADV1FEcjGSHw4lTg1Wx+WMAMdl/7
# nbvfFxJ9uu5tNiT54B0s+lZO/HztwXYQUczdsFon3pjsNrsk9ZlalBi5SHkIu+F6
# g7tWiEv3rtVApmJRnLkUr2Xq2a4nbslUCt4jKs5UX4V1nSX8OM++AXoyVGO+iTj7
# z+pl6XE9Gw/Td6WKKKswgga0MIIEnKADAgECAhANx6xXBf8hmS5AQyIMOkmGMA0G
# CSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
# IFRydXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAwMDBaFw0zODAxMTQyMzU5NTla
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEy
# NTYgMjAyNSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0eDHT
# CphBcr48RsAcrHXbo0ZodLRRF51NrY0NlLWZloMsVO1DahGPNRcybEKq+RuwOnPh
# of6pvF4uGjwjqNjfEvUi6wuim5bap+0lgloM2zX4kftn5B1IpYzTqpyFQ/4Bt0mA
# xAHeHYNnQxqXmRinvuNgxVBdJkf77S2uPoCj7GH8BLuxBG5AvftBdsOECS1UkxBv
# MgEdgkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2Ws3IfDReb6e3mmdglTcaarps
# 0wjUjsZvkgFkriK9tUKJm/s80FiocSk1VYLZlDwFt+cVFBURJg6zMUjZa/zbCclF
# 83bRVFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9oHRaQT/aofEnS5xLrfxnGpTXi
# UOeSLsJygoLPp66bkDX1ZlAeSpQl92QOMeRxykvq6gbylsXQskBBBnGy3tW/AMOM
# CZIVNSaz7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+rx3rKWDEJlIqLXvJWnY0v5ydP
# pOjL6s36czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvUBDx6z1ev+7psNOdgJMoiwOrU
# G2ZdSoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl9VnePs6BaaeEWvjJSjNm2qA+
# sdFUeEY0qVjPKOWug/G6X5uAiynM7Bu2ayBjUwIDAQABo4IBXTCCAVkwEgYDVR0T
# AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU729TSunkBnx6yuKQVvYv1Ensy04wHwYD
# VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG
# A1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV
# HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
# cnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1s
# BwEwDQYJKoZIhvcNAQELBQADggIBABfO+xaAHP4HPRF2cTC9vgvItTSmf83Qh8WI
# GjB/T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQM2qEJPe36zwbSI/mS83afsl3YTj+
# IQhQE7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy9lMDPjTLxLgXf9r5nWMQwr8M
# yb9rEVKChHyfpzee5kH0F8HABBgr0UdqirZ7bowe9Vj2AIMD8liyrukZ2iA/wdG2
# th9y1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1UH410ANVko43+Cdmu4y81hjaj
# V/gxdEkMx1NKU4uHQcKfZxAvBAKqMVuqte69M9J6A47OvgRaPs+2ykgcGV00TYr2
# Lr3ty9qIijanrUR3anzEwlvzZiiyfTPjLbnFRsjsYg39OlV8cipDoq7+qNNjqFze
# GxcytL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0vw9vODRzW6AxnJll38F0cuJG
# 7uEBYTptMSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/DJbg3s6KCLPAlZ66RzIg9sC+N
# Jpud/v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHbxtl5TPau1j/1MIDpMPx0LckT
# etiSuEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAPvIXKUjPSxyZsq8WhbaM2tszW
# kPZPubdcMIIG7TCCBNWgAwIBAgIQCoDvGEuN8QWC0cR2p5V0aDANBgkqhkiG9w0B
# AQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/
# BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYg
# U0hBMjU2IDIwMjUgQ0ExMB4XDTI1MDYwNDAwMDAwMFoXDTM2MDkwMzIzNTk1OVow
# YzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQD
# EzJEaWdpQ2VydCBTSEEyNTYgUlNBNDA5NiBUaW1lc3RhbXAgUmVzcG9uZGVyIDIw
# MjUgMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANBGrC0Sxp7Q6q5g
# VrMrV7pvUf+GcAoB38o3zBlCMGMyqJnfFNZx+wvA69HFTBdwbHwBSOeLpvPnZ8ZN
# +vo8dE2/pPvOx/Vj8TchTySA2R4QKpVD7dvNZh6wW2R6kSu9RJt/4QhguSssp3qo
# me7MrxVyfQO9sMx6ZAWjFDYOzDi8SOhPUWlLnh00Cll8pjrUcCV3K3E0zz09ldQ/
# /nBZZREr4h/GI6Dxb2UoyrN0ijtUDVHRXdmncOOMA3CoB/iUSROUINDT98oksouT
# MYFOnHoRh6+86Ltc5zjPKHW5KqCvpSduSwhwUmotuQhcg9tw2YD3w6ySSSu+3qU8
# DD+nigNJFmt6LAHvH3KSuNLoZLc1Hf2JNMVL4Q1OpbybpMe46YceNA0LfNsnqcnp
# JeItK/DhKbPxTTuGoX7wJNdoRORVbPR1VVnDuSeHVZlc4seAO+6d2sC26/PQPdP5
# 1ho1zBp+xUIZkpSFA8vWdoUoHLWnqWU3dCCyFG1roSrgHjSHlq8xymLnjCbSLZ49
# kPmk8iyyizNDIXj//cOgrY7rlRyTlaCCfw7aSUROwnu7zER6EaJ+AliL7ojTdS5P
# WPsWeupWs7NpChUk555K096V1hE0yZIXe+giAwW00aHzrDchIc2bQhpp0IoKRR7Y
# ufAkprxMiXAJQ1XCmnCfgPf8+3mnAgMBAAGjggGVMIIBkTAMBgNVHRMBAf8EAjAA
# MB0GA1UdDgQWBBTkO/zyMe39/dfzkXFjGVBDz2GM6DAfBgNVHSMEGDAWgBTvb1NK
# 6eQGfHrK4pBW9i/USezLTjAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYI
# KwYBBQUHAwgwgZUGCCsGAQUFBwEBBIGIMIGFMCQGCCsGAQUFBzABhhhodHRwOi8v
# b2NzcC5kaWdpY2VydC5jb20wXQYIKwYBBQUHMAKGUWh0dHA6Ly9jYWNlcnRzLmRp
# Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRpbWVTdGFtcGluZ1JTQTQwOTZT
# SEEyNTYyMDI1Q0ExLmNydDBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vY3JsMy5k
# aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2
# U0hBMjU2MjAyNUNBMS5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9
# bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQBlKq3xHCcEua5gQezRCESeY0ByIfjk9iJP
# 2zWLpQq1b4URGnwWBdEZD9gBq9fNaNmFj6Eh8/YmRDfxT7C0k8FUFqNh+tshgb4O
# 6Lgjg8K8elC4+oWCqnU/ML9lFfim8/9yJmZSe2F8AQ/UdKFOtj7YMTmqPO9mzskg
# iC3QYIUP2S3HQvHG1FDu+WUqW4daIqToXFE/JQ/EABgfZXLWU0ziTN6R3ygQBHMU
# BaB5bdrPbF6MRYs03h4obEMnxYOX8VBRKe1uNnzQVTeLni2nHkX/QqvXnNb+YkDF
# kxUGtMTaiLR9wjxUxu2hECZpqyU1d0IbX6Wq8/gVutDojBIFeRlqAcuEVT0cKsb+
# zJNEsuEB7O7/cuvTQasnM9AWcIQfVjnzrvwiCZ85EE8LUkqRhoS3Y50OHgaY7T/l
# wd6UArb+BOVAkg2oOvol/DJgddJ35XTxfUlQ+8Hggt8l2Yv7roancJIFcbojBcxl
# RcGG0LIhp6GvReQGgMgYxQbV1S3CrWqZzBt1R9xJgKf47CdxVRd/ndUlQ05oxYy2
# zRWVFjF7mcr4C34Mj3ocCVccAvlKV9jEnstrniLvUxxVZE/rptb7IRE2lskKPIJg
# baP5t2nGj/ULLi49xTcBZU8atufk+EMF/cWuiC7POGT75qaL6vdCvHlshtjdNXOC
# IUjsarfNZzGCBkQwggZAAgEBMGgwVDELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1Nl
# Y3RpZ28gTGltaXRlZDErMCkGA1UEAxMiU2VjdGlnbyBQdWJsaWMgQ29kZSBTaWdu
# aW5nIENBIFIzNgIQB5zg5NEUf4XNOXPPdi036zANBglghkgBZQMEAgEFAKCBhDAY
# BgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3
# AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEi
# BCAoQAflKZ7GO1nxXmB/kFeXnhpAFyfbQGyoT1sbJmuC+TANBgkqhkiG9w0BAQEF
# AASCAgCaIec+F8YGNPtdJbGvaqytrep82e+jqGfJ6pd+3mKYMsnBm0L7A9e1xcW5
# Bbm8dkP2hTY2gTksg97paMh5ScU9Rs/dQhWazJfz9SpgFN68VmDwOXWC1VFh2Cob
# bKBaY8DcoiueQ/fjQQyZkl7Bm0h19Zpoxy147vSO6/k04BycDeUr97PDFA2oFVkW
# k07H1z0FP66v++ohI5Tg0/h/5P4EvEXjj1Pna80C+LYffZs0wVN0sec9AEjEplQL
# rOQMOtftQj859qKahUo5vd2EjT2gngAKmK2I1GdK5a1o5oyfpoquQGRtTNMpDTGo
# t+9/Rv5ioLeQJ+as6iL7p64T3g2BsQk4hvIca3JG60vM4zCl2YIRzcClhqSp+U9Z
# FmY8lEPJC+KCI+KhUby/sq76xQ2fnmqpJFCrcjxkVlp8h5QqHES5Exb/UEokTvxj
# 0QgtH4zdcIIW2AYo7sE2YFE3CNOfs9REvlcgpyaMxcR6DhIFGCukabbyOFaeQWaj
# hQhgL2WMvhHsJqx7MTrz6BZGEMN6muPW+3EExoC59uro4FalnIHa0QH7hrWw+Jjf
# GdLwAR86YV6YUmjSgKT0q74DXtSZ/aARF8YPrYMHPKAdrqthhGDrx8D36LNwM6Xi
# O5cV1DYH3qL9M4MKdsa9+dMFzbi3Dbear0DmDplZ+YuLYPa//qGCAyYwggMiBgkq
# hkiG9w0BCQYxggMTMIIDDwIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5E
# aWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1l
# U3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTECEAqA7xhLjfEFgtHEdqeV
# dGgwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwG
# CSqGSIb3DQEJBTEPFw0yNjA1MjQxNzQxMTJaMC8GCSqGSIb3DQEJBDEiBCAeyuf4
# sOQlGdVy6U11LMRj6nk8jscmios+k8G553GJZjANBgkqhkiG9w0BAQEFAASCAgBt
# doJAPSgzYZesQAwXRtpVl8tBvKCOxt8d39YjWZNapUL8XDENpyvX3qqxybDiE4h9
# hwIT7DSJiJU/TKvPVi8vRKh9XHSiUdefVGYYWSRqP4kgyjUPqN6/5boDJSt/Fo/X
# 7zdPBwt2mDEugd/KOaqHJ9PQbLY6j8geeIRmjI+qaSjfZtBOZJUad14lSNr2Zjds
# 2QXvssmgeeRfAEOuLxWN9MlfKes4kiC1112x/XcUV+MPyft9xZSNNt6GcDRvVTvB
# gIlBdtKHqaZXyWr1w2J17WPp27NiMiPsosSX2HBOyI0T/Hn+0nlYR/Tcyl5jTY5X
# E0hd+HrqG+LD8C+PsG83d4hQwLvlVr3AfJzSOSQ+Qn1+EWxcPcPncaHencVzx67F
# VFfph0Rj1dERMa4zdyk+C7yemi5/WjjnwsCYX5COf2YTm3Pl9xaR37y9rRgBu5Vy
# yrERerao0ui0z+yG9LF4lBfwECRcroodD3krsUQnOxFGIr1R5C7YN565r3keEtud
# 0X9KXf0hhekMHnE4gL3bBfINSf0FRf+Wfzvxr1RK9HsnZMARLq1ftYqgBFX1Q/Tr
# OyEIW5NdzJOIWHmBGqn+pJaqv+oCvV9NrN/XgRNceQk2263sNzTTOIdL0uXS/npK
# GulSMaehgI2LZ/4uXsdcUlBHNbf2yguW+PBmBasJTg==
# SIG # End signature block