Runtime/SmartM365.GuiSplash.ps1

function Initialize-SmartM365NativeWindowApi {
    if ('SmartM365.NativeWindow' -as [type]) { return }

    Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
namespace SmartM365 {
    public static class NativeWindow {
        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
 
        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
    }
}
'@

}

function Set-SmartM365WpfWindowVisible {
    [CmdletBinding()]
    param([Parameter(Mandatory = $true)]$Window)

    try {
        Initialize-SmartM365NativeWindowApi
        $helper = [System.Windows.Interop.WindowInteropHelper]::new($Window)
        if ($helper.Handle -ne [IntPtr]::Zero) {
            [void][SmartM365.NativeWindow]::ShowWindow($helper.Handle, 5)
            [void][SmartM365.NativeWindow]::SetForegroundWindow($helper.Handle)
        }
        $Window.Visibility = [System.Windows.Visibility]::Visible
        [void]$Window.Activate()
    }
    catch {}
}

function Start-SmartM365GuiSplash {
    [CmdletBinding()]
    param(
        [ValidateSet('Wpf')]
        [string]$Framework = 'Wpf',

        [string]$ProductName = 'SmartM365',

        [int]$MinimumDurationMs = 6000,

        [string]$BadgeText = 'WORKPLACECLOUDHUB.COM',

        [string]$Subtitle = 'Powered by WorkplaceCloudHub',

        [string]$LogoPath = '',

        [string]$WindowIconPath = '',

        [bool]$ShowSiteUrl = $true
    )

    $siteUrl = 'https://workplacecloudhub.com'
    $startedAt = Get-Date

    Add-Type -AssemblyName PresentationCore
    Add-Type -AssemblyName PresentationFramework
    Add-Type -AssemblyName WindowsBase

    $accentBrush = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.Color]::FromRgb(0, 120, 212))
    $inkBrush = [System.Windows.Media.Brushes]::White
    $mutedBrush = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.Color]::FromRgb(214, 233, 250))
    $linkBrush = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.Color]::FromRgb(188, 231, 255))
    $borderBrush = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.Color]::FromRgb(118, 184, 235))
    $surfaceBrush = [System.Windows.Media.LinearGradientBrush]::new()
    $surfaceBrush.StartPoint = [System.Windows.Point]::new(0, 0)
    $surfaceBrush.EndPoint = [System.Windows.Point]::new(1, 1)
    [void]$surfaceBrush.GradientStops.Add([System.Windows.Media.GradientStop]::new([System.Windows.Media.Color]::FromRgb(5, 32, 66), 0.0))
    [void]$surfaceBrush.GradientStops.Add([System.Windows.Media.GradientStop]::new([System.Windows.Media.Color]::FromRgb(0, 91, 159), 0.58))
    [void]$surfaceBrush.GradientStops.Add([System.Windows.Media.GradientStop]::new([System.Windows.Media.Color]::FromRgb(0, 145, 204), 1.0))

    $workplaceLogoPath = $null
    $resolvedWindowIconPath = $null
    if (-not [string]::IsNullOrWhiteSpace($LogoPath)) {
        $candidate = if ([System.IO.Path]::IsPathRooted($LogoPath)) { $LogoPath } else { Join-Path -Path $PSScriptRoot -ChildPath $LogoPath }
        if (Test-Path -LiteralPath $candidate -PathType Leaf) {
            $workplaceLogoPath = $candidate
        }
    }

    if (-not [string]::IsNullOrWhiteSpace($WindowIconPath)) {
        $candidate = if ([System.IO.Path]::IsPathRooted($WindowIconPath)) { $WindowIconPath } else { Join-Path -Path $PSScriptRoot -ChildPath $WindowIconPath }
        if (Test-Path -LiteralPath $candidate -PathType Leaf) {
            $resolvedWindowIconPath = $candidate
        }
    }

    $logoSearchRoot = $PSScriptRoot
    while ($logoSearchRoot) {
        $candidate = Join-Path -Path $logoSearchRoot -ChildPath 'WorkplaceCloudHub-lockup-WPF.png'
        if (-not $workplaceLogoPath -and (Test-Path -LiteralPath $candidate -PathType Leaf)) {
            $workplaceLogoPath = $candidate
        }

        $iconCandidate = Join-Path -Path $logoSearchRoot -ChildPath 'WorkplaceCloudHub.ico'
        if (-not $resolvedWindowIconPath -and (Test-Path -LiteralPath $iconCandidate -PathType Leaf)) {
            $resolvedWindowIconPath = $iconCandidate
        }

        if ($workplaceLogoPath -and $resolvedWindowIconPath) { break }

        $parent = Split-Path -Parent $logoSearchRoot
        if ([string]::IsNullOrWhiteSpace($parent) -or $parent -eq $logoSearchRoot) {
            break
        }

        $logoSearchRoot = $parent
    }

    if (-not $workplaceLogoPath) {
        $smartM365Root = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
        foreach ($relativePath in @(
            'Devices\IntuneHybridJoinToolkit\WorkplaceCloudHub-lockup-WPF.png',
            'Devices\Windows11UpgradeToolkit\WorkplaceCloudHub-lockup-WPF.png',
            'Devices\DeviceRegistrationTool\WorkplaceCloudHub-lockup-WPF.png',
            'Devices\EndpointDiagnosticsAnalyzer\WorkplaceCloudHub-lockup-WPF.png'
        )) {
            $candidate = Join-Path $smartM365Root $relativePath
            if (Test-Path -LiteralPath $candidate -PathType Leaf) {
                $workplaceLogoPath = $candidate
                break
            }
        }
    }

    if (-not $resolvedWindowIconPath) {
        $smartM365Root = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
        foreach ($relativePath in @(
            'Devices\IntuneHybridJoinToolkit\WorkplaceCloudHub.ico',
            'Devices\Windows11UpgradeToolkit\WorkplaceCloudHub.ico',
            'Devices\DeviceRegistrationTool\WorkplaceCloudHub.ico',
            'Devices\EndpointDiagnosticsAnalyzer\WorkplaceCloudHub.ico',
            'Devices\DeviceRebootManager\WorkplaceCloudHub.ico',
            'Intune\Remediation\GUI\WorkplaceCloudHub.ico',
            'WorkplaceCloudHub.ico'
        )) {
            $candidate = Join-Path $smartM365Root $relativePath
            if (Test-Path -LiteralPath $candidate -PathType Leaf) {
                $resolvedWindowIconPath = $candidate
                break
            }
        }
    }

    $rootGrid = [System.Windows.Controls.Grid]::new()
    $rootGrid.Margin = [System.Windows.Thickness]::new(26, 22, 26, 20)
    [void]$rootGrid.ColumnDefinitions.Add([System.Windows.Controls.ColumnDefinition]::new())
    $logoColumn = [System.Windows.Controls.ColumnDefinition]::new()
    $logoColumn.Width = [System.Windows.GridLength]::new(210)
    [void]$rootGrid.ColumnDefinitions.Add($logoColumn)

    $panel = [System.Windows.Controls.StackPanel]::new()
    [System.Windows.Controls.Grid]::SetColumn($panel, 0)
    [void]$rootGrid.Children.Add($panel)

    $logoStack = [System.Windows.Controls.StackPanel]::new()
    $logoStack.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Center
    $logoStack.VerticalAlignment = [System.Windows.VerticalAlignment]::Center
    $logoStack.Margin = [System.Windows.Thickness]::new(18, 0, 0, 0)
    [System.Windows.Controls.Grid]::SetColumn($logoStack, 1)
    [void]$rootGrid.Children.Add($logoStack)

    if ($workplaceLogoPath) {
        try {
            $bitmap = [System.Windows.Media.Imaging.BitmapImage]::new()
            $bitmap.BeginInit()
            $bitmap.CacheOption = [System.Windows.Media.Imaging.BitmapCacheOption]::OnLoad
            $bitmap.UriSource = [Uri]$workplaceLogoPath
            $bitmap.EndInit()
            $bitmap.Freeze()

            $workplaceLogo = [System.Windows.Controls.Image]::new()
            $workplaceLogo.Source = $bitmap
            $workplaceLogo.Width = 178
            $workplaceLogo.Height = 178
            $workplaceLogo.Stretch = [System.Windows.Media.Stretch]::Uniform
            $workplaceLogo.SnapsToDevicePixels = $true
            [System.Windows.Media.RenderOptions]::SetBitmapScalingMode($workplaceLogo, [System.Windows.Media.BitmapScalingMode]::HighQuality)
            [void]$logoStack.Children.Add($workplaceLogo)
        }
        catch {}
    }

    $badge = [System.Windows.Controls.TextBlock]::new()
    $badge.Text = $BadgeText
    $badge.Foreground = $linkBrush
    $badge.FontSize = 11
    $badge.FontWeight = [System.Windows.FontWeights]::SemiBold
    if (-not [string]::IsNullOrWhiteSpace($BadgeText)) {
        [void]$panel.Children.Add($badge)
    }

    $title = [System.Windows.Controls.TextBlock]::new()
    $title.Text = $ProductName
    $title.Foreground = $inkBrush
    $title.FontSize = 24
    $title.FontWeight = [System.Windows.FontWeights]::SemiBold
    $title.Margin = [System.Windows.Thickness]::new(0, 8, 0, 4)
    [void]$panel.Children.Add($title)

    $subtitleTextBlock = [System.Windows.Controls.TextBlock]::new()
    $subtitleTextBlock.Text = $Subtitle
    $subtitleTextBlock.Foreground = $mutedBrush
    $subtitleTextBlock.FontSize = 13
    $subtitleTextBlock.Margin = [System.Windows.Thickness]::new(0, 0, 0, 12)
    if (-not [string]::IsNullOrWhiteSpace($Subtitle)) {
        [void]$panel.Children.Add($subtitleTextBlock)
    }

    if ($ShowSiteUrl) {
        foreach ($url in @($siteUrl)) {
            $line = [System.Windows.Controls.TextBlock]::new()
            $line.Text = $url
            $line.Foreground = $linkBrush
            $line.FontSize = 12
            $line.Margin = [System.Windows.Thickness]::new(0, 0, 0, 4)
            [void]$panel.Children.Add($line)
        }
    }

    $border = [System.Windows.Controls.Border]::new()
    $border.Background = $surfaceBrush
    $border.BorderBrush = $borderBrush
    $border.BorderThickness = [System.Windows.Thickness]::new(1)
    $border.CornerRadius = [System.Windows.CornerRadius]::new(8)
    $border.Child = $rootGrid

    $window = [System.Windows.Window]::new()
    $window.Title = 'WorkplaceCloudHub'
    $window.Width = 720
    $window.Height = 292
    $window.WindowStartupLocation = 'CenterScreen'
    $window.ResizeMode = 'NoResize'
    $window.ShowInTaskbar = $false
    $window.Topmost = $true
    $window.UseLayoutRounding = $true
    $window.SnapsToDevicePixels = $true
    $window.Content = $border
    if ($resolvedWindowIconPath) {
        try {
            $window.Icon = [System.Windows.Media.Imaging.BitmapFrame]::Create([Uri]$resolvedWindowIconPath)
        }
        catch {}
    }
    $window.Show()
    Set-SmartM365WpfWindowVisible -Window $window

    try {
        $window.Dispatcher.Invoke([Action]{}, [System.Windows.Threading.DispatcherPriority]::ApplicationIdle)
    }
    catch {}

    return [pscustomobject]@{
        Framework = $Framework
        Window = $window
        StartedAt = $startedAt
        MinimumDurationMs = $MinimumDurationMs
    }
}

function Wait-SmartM365GuiSplashMinimum {
    [CmdletBinding()]
    param([Parameter(Mandatory = $true)]$Splash)

    while ($true) {
        $elapsedMs = [int]((Get-Date) - [datetime]$Splash.StartedAt).TotalMilliseconds
        $remainingMs = [int]$Splash.MinimumDurationMs - $elapsedMs
        if ($remainingMs -le 0) {
            break
        }

        try {
            if ($Splash.Window -and $Splash.Window.Dispatcher) {
                $Splash.Window.Dispatcher.Invoke([Action]{}, [System.Windows.Threading.DispatcherPriority]::Background)
            }
        }
        catch {}

        Start-Sleep -Milliseconds ([math]::Min(100, $remainingMs))
    }
}

function Hide-SmartM365GuiSplash {
    [CmdletBinding()]
    param([AllowNull()]$Splash)

    if ($null -eq $Splash -or $null -eq $Splash.Window) { return }
    Wait-SmartM365GuiSplashMinimum -Splash $Splash

    try {
        $Splash.Window.Topmost = $false
        $Splash.Window.Hide()
    }
    catch {}
}

function Close-SmartM365GuiSplash {
    [CmdletBinding()]
    param([AllowNull()]$Splash)

    if ($null -eq $Splash -or $null -eq $Splash.Window) { return }
    Wait-SmartM365GuiSplashMinimum -Splash $Splash

    try {
        $Splash.Window.Close()
    }
    catch {}
}

# SIG # Begin signature block
# MIIeYwYJKoZIhvcNAQcCoIIeVDCCHlACAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDj4fU0+Ki+Y4jg
# Mb/hGc0OzE+Wka2A8u6MrN8ugBAGNqCCF/swggS9MIIDJaADAgECAhAebu87xzjh
# s0Q4yPEDH+JoMA0GCSqGSIb3DQEBCwUAME4xHjAcBgNVBAMMFXdvcmtwbGFjZWNs
# b3VkaHViLmNvbTEsMCoGCSqGSIb3DQEJARYdY29udGFjdEB3b3JrcGxhY2VjbG91
# ZGh1Yi5jb20wHhcNMjYwNzEzMDgyMjM1WhcNMjkwNzEzMDgzMjI5WjBOMR4wHAYD
# VQQDDBV3b3JrcGxhY2VjbG91ZGh1Yi5jb20xLDAqBgkqhkiG9w0BCQEWHWNvbnRh
# Y3RAd29ya3BsYWNlY2xvdWRodWIuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8A
# MIIBigKCAYEAse6XztERSyHn9DVqj8Rdv0qjc5owqvgAIGaYxBmfiQuoM48Fo4Xt
# 1ovi9brLUtf55G4XgthNPCoanxfCRRg30IVRxaDfdPXJzYmgsM5tXlsuNU49lE7E
# PJk3+jEOgSCt8NKzmVPKpNRG0NmK0a8wm12cceYZOZlSYE0+ZtT6wy5PQQjMUqIx
# XnGjt4H0nfgZZa7D4FyARKOVg/Xr9sUq5jIn3zszvg4jjeb4b0DKJtfbHukhWc2Y
# oVFgswxVBXCWIaBnfF/cjqMfK/CaToT2trVb4hG4qcQ31s1nR4keoRaOw/vyd6ap
# rEtCsT22N/Jx0dz7fIo1tVyvIaVcHdN9LW3chn0en0OKZ6Ke1OH9wf2prl4KA6Ww
# VzrAZrOlXTAItdK7D9kKO/HeJd4PZvO53oy1LdmMGLSz3OLB9e5q7yo8rfqi5Ka9
# KzM2CrSzz1yphn/H90wz7Q2pm4FIlWdcj86A/0kmhYg+5Wqqbg1drrPXu4nEBwWN
# /dzoGtKZKHTdAgMBAAGjgZYwgZMwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
# CCsGAQUFBwMDMD8GA1UdEQQ4MDaBHWNvbnRhY3RAd29ya3BsYWNlY2xvdWRodWIu
# Y29tghV3b3JrcGxhY2VjbG91ZGh1Yi5jb20wDAYDVR0TAQH/BAIwADAdBgNVHQ4E
# FgQUXIOOADQM78XfPAncirgCECedg9gwDQYJKoZIhvcNAQELBQADggGBADhZUB2R
# 5J/Jw030xodhEWeCQ0vnJRaiEsjOxuArQREKH3lCrQ3UsUVl292d6LnQUSTH/jF7
# rovEZ+JN2GQ/LCrXRaCuwCEGZKzlSEbtYWhfwDyj6GpIPq8Y4SeXyjdq4/rrI1bm
# iTK4Sq7EoBlGJuX6l2nfvx1tTioSr11FoDfllJR7EYawRj9hBFJ0gG0b2SuYZMgW
# gaDKefcnJDmOwcRNAZUII0ss8EeyANukWSkNN5ILZ+iKDpQgZxgDLPTiRguCyx45
# PI5wrVTjV/pR7IrtSIfq8UladlrSZJyyDn3NV2ATvIZ6wNxbTmPFcE0uMg/EYzwd
# Tek+CgXL3TxUKeldJM4YDWPimNBRhOPXzBDiOQIj6WNswt/KM1oDLnA00CNtciPN
# dn+dXlneMvTEUah9wyt8o8tkLpoBw+KN+Bq/K0O1qPtS7umi70l45pPiej+mwbwq
# ztcaoVD7a8ggHP1Vdp/rnafM4GtyCAE6b7U9Yzgvp1/a1kh7XffmqVhRRjCCBY0w
# ggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZIhvcNAQEMBQAwZTELMAkG
# A1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRp
# Z2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENB
# MB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVowYjELMAkGA1UEBhMCVVMx
# FTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv
# bTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MIICIjANBgkqhkiG
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjwwIjBpM+zCpyUuySE98orY
# WcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J58soR0uRf1gU8Ug9SH8ae
# FaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMHhOZ0O21x4i0MG+4g1ckg
# HWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6Zu53yEioZldXn1RYjgwr
# t0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQecN4x7axxLVqGDgDEI3Y
# 1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4bA3VdeGbZOjFEmjNAvwjX
# WkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9WV1CdoeJl2l6SPDgohIb
# Zpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCUtNJhbesz2cXfSwQAzH0c
# lcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvoZKYz0YkH4b235kOkGLim
# dwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/JvNNBERJb5RBQ6zHFynIW
# IgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCPorF+CiaZ9eRpL5gdLfXZ
# qbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOzX
# 44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3z
# bcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGG
# GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2Nh
# Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDBF
# BgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNl
# cnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG
# 9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cHvZqsoYcs7IVeqRq7IviH
# GmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8UgPITtAq3votVs/59Pes
# MHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTnf+hZqPC/Lwum6fI0POz3
# A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxUjG/voVA9/HYJaISfb8rb
# II01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8jLfR+cWojayL/ErhULSd+
# 2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDCCBrQwggScoAMCAQICEA3HrFcF
# /yGZLkBDIgw6SYYwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNV
# BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8G
# A1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4XDTI1MDUwNzAwMDAwMFoX
# DTM4MDExNDIzNTk1OVowaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0
# LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGlu
# ZyBSU0E0MDk2IFNIQTI1NiAyMDI1IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
# ADCCAgoCggIBALR4MdMKmEFyvjxGwBysddujRmh0tFEXnU2tjQ2UtZmWgyxU7UNq
# EY81FzJsQqr5G7A6c+Gh/qm8Xi4aPCOo2N8S9SLrC6Kbltqn7SWCWgzbNfiR+2fk
# HUiljNOqnIVD/gG3SYDEAd4dg2dDGpeZGKe+42DFUF0mR/vtLa4+gKPsYfwEu7EE
# bkC9+0F2w4QJLVSTEG8yAR2CQWIM1iI5PHg62IVwxKSpO0XaF9DPfNBKS7Zazch8
# NF5vp7eaZ2CVNxpqumzTCNSOxm+SAWSuIr21Qomb+zzQWKhxKTVVgtmUPAW35xUU
# FREmDrMxSNlr/NsJyUXzdtFUUt4aS4CEeIY8y9IaaGBpPNXKFifinT7zL2gdFpBP
# 9qh8SdLnEut/GcalNeJQ55IuwnKCgs+nrpuQNfVmUB5KlCX3ZA4x5HHKS+rqBvKW
# xdCyQEEGcbLe1b8Aw4wJkhU1JrPsFfxW1gaou30yZ46t4Y9F20HHfIY4/6vHespY
# MQmUiote8ladjS/nJ0+k6MvqzfpzPDOy5y6gqztiT96Fv/9bH7mQyogxG9QEPHrP
# V6/7umw052AkyiLA6tQbZl1KhBtTasySkuJDpsZGKdlsjg4u70EwgWbVRSX1Wd4+
# zoFpp4Ra+MlKM2baoD6x0VR4RjSpWM8o5a6D8bpfm4CLKczsG7ZrIGNTAgMBAAGj
# ggFdMIIBWTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTvb1NK6eQGfHrK
# 4pBW9i/USezLTjAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNV
# HQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBp
# MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUH
# MAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRS
# b290RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EM
# AQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAF877FoAc/gc9EXZx
# ML2+C8i1NKZ/zdCHxYgaMH9Pw5tcBnPw6O6FTGNpoV2V4wzSUGvI9NAzaoQk97fr
# PBtIj+ZLzdp+yXdhOP4hCFATuNT+ReOPK0mCefSG+tXqGpYZ3essBS3q8nL2UwM+
# NMvEuBd/2vmdYxDCvwzJv2sRUoKEfJ+nN57mQfQXwcAEGCvRR2qKtntujB71WPYA
# gwPyWLKu6RnaID/B0ba2H3LUiwDRAXx1Neq9ydOal95CHfmTnM4I+ZI2rVQfjXQA
# 1WSjjf4J2a7jLzWGNqNX+DF0SQzHU0pTi4dBwp9nEC8EAqoxW6q17r0z0noDjs6+
# BFo+z7bKSBwZXTRNivYuve3L2oiKNqetRHdqfMTCW/NmKLJ9M+MtucVGyOxiDf06
# VXxyKkOirv6o02OoXN4bFzK0vlNMsvhlqgF2puE6FndlENSmE+9JGYxOGLS/D284
# NHNboDGcmWXfwXRy4kbu4QFhOm0xJuF2EZAOk5eCkhSxZON3rGlHqhpB/8MluDez
# ooIs8CVnrpHMiD2wL40mm53+/j7tFaxYKIqL0Q4ssd8xHZnIn/7GELH3IdvG2XlM
# 9q7WP/UwgOkw/HQtyRN62JK4S1C8uw3PdBunvAZapsiI5YKdvlarEvf8EA+8hcpS
# M9LHJmyrxaFtoza2zNaQ9k+5t1wwggbtMIIE1aADAgECAhAKgO8YS43xBYLRxHan
# lXRoMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp
# Q2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3Rh
# bXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwHhcNMjUwNjA0MDAwMDAwWhcN
# MzYwOTAzMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs
# IEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFNIQTI1NiBSU0E0MDk2IFRpbWVzdGFt
# cCBSZXNwb25kZXIgMjAyNSAxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
# AgEA0EasLRLGntDqrmBWsytXum9R/4ZwCgHfyjfMGUIwYzKomd8U1nH7C8Dr0cVM
# F3BsfAFI54um8+dnxk36+jx0Tb+k+87H9WPxNyFPJIDZHhAqlUPt281mHrBbZHqR
# K71Em3/hCGC5KyyneqiZ7syvFXJ9A72wzHpkBaMUNg7MOLxI6E9RaUueHTQKWXym
# OtRwJXcrcTTPPT2V1D/+cFllESviH8YjoPFvZSjKs3SKO1QNUdFd2adw44wDcKgH
# +JRJE5Qg0NP3yiSyi5MxgU6cehGHr7zou1znOM8odbkqoK+lJ25LCHBSai25CFyD
# 23DZgPfDrJJJK77epTwMP6eKA0kWa3osAe8fcpK40uhktzUd/Yk0xUvhDU6lvJuk
# x7jphx40DQt82yepyekl4i0r8OEps/FNO4ahfvAk12hE5FVs9HVVWcO5J4dVmVzi
# x4A77p3awLbr89A90/nWGjXMGn7FQhmSlIUDy9Z2hSgctaepZTd0ILIUbWuhKuAe
# NIeWrzHKYueMJtItnj2Q+aTyLLKLM0MheP/9w6CtjuuVHJOVoIJ/DtpJRE7Ce7vM
# RHoRon4CWIvuiNN1Lk9Y+xZ66lazs2kKFSTnnkrT3pXWETTJkhd76CIDBbTRofOs
# NyEhzZtCGmnQigpFHti58CSmvEyJcAlDVcKacJ+A9/z7eacCAwEAAaOCAZUwggGR
# MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOQ7/PIx7f391/ORcWMZUEPPYYzoMB8G
# A1UdIwQYMBaAFO9vU0rp5AZ8esrikFb2L9RJ7MtOMA4GA1UdDwEB/wQEAwIHgDAW
# BgNVHSUBAf8EDDAKBggrBgEFBQcDCDCBlQYIKwYBBQUHAQEEgYgwgYUwJAYIKwYB
# BQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBdBggrBgEFBQcwAoZRaHR0
# cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGltZVN0
# YW1waW5nUlNBNDA5NlNIQTI1NjIwMjVDQTEuY3J0MF8GA1UdHwRYMFYwVKBSoFCG
# Tmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRpbWVT
# dGFtcGluZ1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNybDAgBgNVHSAEGTAXMAgGBmeB
# DAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAGUqrfEcJwS5rmBB
# 7NEIRJ5jQHIh+OT2Ik/bNYulCrVvhREafBYF0RkP2AGr181o2YWPoSHz9iZEN/FP
# sLSTwVQWo2H62yGBvg7ouCODwrx6ULj6hYKqdT8wv2UV+Kbz/3ImZlJ7YXwBD9R0
# oU62PtgxOao872bOySCILdBghQ/ZLcdC8cbUUO75ZSpbh1oipOhcUT8lD8QAGB9l
# ctZTTOJM3pHfKBAEcxQFoHlt2s9sXoxFizTeHihsQyfFg5fxUFEp7W42fNBVN4ue
# LaceRf9Cq9ec1v5iQMWTFQa0xNqItH3CPFTG7aEQJmmrJTV3Qhtfparz+BW60OiM
# EgV5GWoBy4RVPRwqxv7Mk0Sy4QHs7v9y69NBqycz0BZwhB9WOfOu/CIJnzkQTwtS
# SpGGhLdjnQ4eBpjtP+XB3pQCtv4E5UCSDag6+iX8MmB10nfldPF9SVD7weCC3yXZ
# i/uuhqdwkgVxuiMFzGVFwYbQsiGnoa9F5AaAyBjFBtXVLcKtapnMG3VH3EmAp/js
# J3FVF3+d1SVDTmjFjLbNFZUWMXuZyvgLfgyPehwJVxwC+UpX2MSey2ueIu9THFVk
# T+um1vshETaWyQo8gmBto/m3acaP9QsuLj3FNwFlTxq25+T4QwX9xa6ILs84ZPvm
# povq90K8eWyG2N01c4IhSOxqt81nMYIFvjCCBboCAQEwYjBOMR4wHAYDVQQDDBV3
# b3JrcGxhY2VjbG91ZGh1Yi5jb20xLDAqBgkqhkiG9w0BCQEWHWNvbnRhY3RAd29y
# a3BsYWNlY2xvdWRodWIuY29tAhAebu87xzjhs0Q4yPEDH+JoMA0GCWCGSAFlAwQC
# AQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwG
# CisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZI
# hvcNAQkEMSIEIJh6u4VD+3o2pg47hyFWuVohHUU1oy9boH3U9CKwELSCMA0GCSqG
# SIb3DQEBAQUABIIBgBlV6FC8wQtc+z7w74iwBi4lp3jaMuhRlPUrGLG3Vr0NF04U
# 295itxcAet4MRczflglT4TjQNlLL3lRCIA8zXNt8TVmfN/ku3+kuXrvsWE/1ZS4Y
# 4SMmUsUQ0hpw7A7MfEt80YtPhOX9deGpFw3uFP0yGYQmgphsw4XPZnIB2qKEdY4Q
# Vjo6l1CMlCN7csAeSrMitf02kQbypP+MSvm6A3fmL7ef61Z6p22TssGZTkzTLEvM
# +Ap/pTJLXWZko5415dvcBAmb/nqfHr9CbtCrjH4eeLfOrCCrAcS3ndt4NhjcrFUl
# Is5r5SuHdo3WTPK79bSZUkISHWph34XNjo1FZu9dAOKOpt8d/oq+KEkNiu6KOWAG
# kG7otKGxyPpQqP2H9crhxgXuK1PCF38y7o5l2g9BftUh/D/UDgAxCS3cBDaRc/La
# nK5KfW3HRC2M2yrGhGX8O3oFb7eaNaTdRQrEE4pUSUajHRnyAE+O4P64E1J+Kcoh
# jimeeR0NwtP4e2shr6GCAyYwggMiBgkqhkiG9w0BCQYxggMTMIIDDwIBATB9MGkx
# CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4
# RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYg
# MjAyNSBDQTECEAqA7xhLjfEFgtHEdqeVdGgwDQYJYIZIAWUDBAIBBQCgaTAYBgkq
# hkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNjA3MTMwODQ5
# MjhaMC8GCSqGSIb3DQEJBDEiBCBsEVHYhL4AT/Di2ID4bGz2RhWMaCSfZvNqCRri
# DFCB+zANBgkqhkiG9w0BAQEFAASCAgBwBqzfJFuElqR2YgGjSkxpljYpEtbVnCzN
# duggim+/+fRyKx0K/mLdtnEIiNKaXkIjxGdloG+ajsjCTVo57PMEDDKOzio+bXX+
# NYOAz6MIiu+FlZMP4P7Be4KeFR+Io/apl3fXJYr9FarTDQLXM8V9Pc6uLgJGqHnu
# F67tn5mVknxQgD5YdKsR31yGvE0FhOp9ft0oHGsKmOgGd7MMPeUupM7CuD4piuu2
# 7ylt6w/RXMP9xT93GsFv9/CbGMcIiUfG0U/9P6qqCcRl4sBfolsz6ir7IUDZjiwo
# jfqkAaUSZNvs1BDKDa2Rb9TapByaxx0FpqF1x9v3Gm5aeN9GOgffyDpJ3GXtZCRc
# leX04Mfi1hZ0x9dG6cio3fzoTBspWro3P2FboDGUSKjHodjH4blSBuztl90CVcdV
# FuXErjn5AZg3//v3Uod5jYdiDhlfYxWF05WQ1uXOQ2XT0Z+uGczdEP0aCm5J1Pvg
# CYYn4Pj2Hd1ou1wZQq77aSqXBkdNHeKqkSL3wtns0UYTqTHZD4BXFwlvvsKxZJfj
# Wvoy0g7Ec06kgEU3XUVrW6Nqtq38F6VieKLY+ZFcy6UGkWmzcmRogs7WYC7mj9a7
# rbncaA8NWzanGujOgjuJhRC8dreL/ouHfVwQ6Klvnp1RW5w4Uc9li+ZeF6JjKH+h
# qN0x8fT2wQ==
# SIG # End signature block