Config/Generate-TechShellAssets.ps1
|
[CmdletBinding()] param( [Parameter(Mandatory)] [string]$SourceImagePath, [string]$SplashSourceImagePath, [string]$AssetsDirectory, [switch]$SkipValidation ) Set-StrictMode -Version 3.0 $ErrorActionPreference = 'Stop' Add-Type -AssemblyName System.Drawing function Resolve-AbsolutePath { param([Parameter(Mandatory)] [string]$Path) if ([System.IO.Path]::IsPathRooted($Path)) { return [System.IO.Path]::GetFullPath($Path) } return [System.IO.Path]::GetFullPath((Join-Path (Get-Location) $Path)) } function New-ScaledImage { param( [Parameter(Mandatory)] [System.Drawing.Image]$Source, [Parameter(Mandatory)] [int]$Width, [Parameter(Mandatory)] [int]$Height, [ValidateSet('crop', 'fit')] [string]$Mode = 'crop' ) $bitmap = New-Object System.Drawing.Bitmap($Width, $Height) $bitmap.SetResolution(96, 96) $graphics = [System.Drawing.Graphics]::FromImage($bitmap) try { $graphics.Clear([System.Drawing.Color]::Transparent) $graphics.CompositingQuality = [System.Drawing.Drawing2D.CompositingQuality]::HighQuality $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic $graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality $sourceRatio = $Source.Width / [double]$Source.Height $targetRatio = $Width / [double]$Height if ($Mode -eq 'crop') { if ($sourceRatio -gt $targetRatio) { $drawHeight = $Height $drawWidth = [int][Math]::Round($Height * $sourceRatio) } else { $drawWidth = $Width $drawHeight = [int][Math]::Round($Width / $sourceRatio) } } else { if ($sourceRatio -gt $targetRatio) { $drawWidth = $Width $drawHeight = [int][Math]::Round($Width / $sourceRatio) } else { $drawHeight = $Height $drawWidth = [int][Math]::Round($Height * $sourceRatio) } } $offsetX = [int][Math]::Floor(($Width - $drawWidth) / 2) $offsetY = [int][Math]::Floor(($Height - $drawHeight) / 2) $graphics.DrawImage($Source, $offsetX, $offsetY, $drawWidth, $drawHeight) } finally { $graphics.Dispose() } return $bitmap } function Save-PngVariant { param( [Parameter(Mandatory)] [System.Drawing.Image]$Source, [Parameter(Mandatory)] [string]$OutputPath, [Parameter(Mandatory)] [int]$Width, [Parameter(Mandatory)] [int]$Height, [ValidateSet('crop', 'fit')] [string]$Mode = 'crop' ) $directory = Split-Path -Parent $OutputPath if (-not (Test-Path -LiteralPath $directory -PathType Container)) { New-Item -ItemType Directory -Path $directory -Force | Out-Null } $scaled = New-ScaledImage -Source $Source -Width $Width -Height $Height -Mode $Mode try { $scaled.Save($OutputPath, [System.Drawing.Imaging.ImageFormat]::Png) } finally { $scaled.Dispose() } } function Get-DetachedImage { param([Parameter(Mandatory)] [string]$Path) $bytes = [System.IO.File]::ReadAllBytes($Path) $memoryStream = New-Object System.IO.MemoryStream(,$bytes) try { $loaded = [System.Drawing.Image]::FromStream($memoryStream) try { return New-Object System.Drawing.Bitmap($loaded) } finally { $loaded.Dispose() } } finally { $memoryStream.Dispose() } } $repoRoot = Split-Path -Parent $PSScriptRoot if ([string]::IsNullOrWhiteSpace($AssetsDirectory)) { $AssetsDirectory = Join-Path $repoRoot 'src\TechShell\src\TechShell.UI\Assets' } $resolvedSourceImagePath = Resolve-AbsolutePath -Path $SourceImagePath if (-not (Test-Path -LiteralPath $resolvedSourceImagePath -PathType Leaf)) { throw "Source image not found: $resolvedSourceImagePath" } $resolvedSplashSourcePath = if ([string]::IsNullOrWhiteSpace($SplashSourceImagePath)) { $resolvedSourceImagePath } else { Resolve-AbsolutePath -Path $SplashSourceImagePath } if (-not (Test-Path -LiteralPath $resolvedSplashSourcePath -PathType Leaf)) { throw "Splash source image not found: $resolvedSplashSourcePath" } $resolvedAssetsDirectory = Resolve-AbsolutePath -Path $AssetsDirectory if (-not (Test-Path -LiteralPath $resolvedAssetsDirectory -PathType Container)) { New-Item -ItemType Directory -Path $resolvedAssetsDirectory -Force | Out-Null } $iconMap = @( @{ Name = 'StoreLogo.png'; Width = 50; Height = 50; Mode = 'crop' }, @{ Name = 'Square44x44Logo.png'; Width = 44; Height = 44; Mode = 'crop' }, @{ Name = 'Square150x150Logo.png'; Width = 150; Height = 150; Mode = 'crop' }, @{ Name = 'Wide310x150Logo.png'; Width = 310; Height = 150; Mode = 'fit' }, @{ Name = 'SplashScreen.png'; Width = 620; Height = 300; Mode = 'fit'; Splash = $true }, @{ Name = 'Square150x150Logo.scale-200.png'; Width = 300; Height = 300; Mode = 'crop' }, @{ Name = 'Square44x44Logo.scale-200.png'; Width = 88; Height = 88; Mode = 'crop' }, @{ Name = 'Wide310x150Logo.scale-200.png'; Width = 620; Height = 300; Mode = 'fit' }, @{ Name = 'SplashScreen.scale-200.png'; Width = 1240; Height = 600; Mode = 'fit'; Splash = $true }, @{ Name = 'LockScreenLogo.scale-200.png'; Width = 48; Height = 48; Mode = 'crop' }, @{ Name = 'Square44x44Logo.targetsize-24_altform-unplated.png'; Width = 24; Height = 24; Mode = 'crop' }, @{ Name = 'Square44x44Logo.targetsize-48_altform-lightunplated.png'; Width = 48; Height = 48; Mode = 'crop' } ) $iconSource = Get-DetachedImage -Path $resolvedSourceImagePath $splashSource = Get-DetachedImage -Path $resolvedSplashSourcePath try { foreach ($entry in $iconMap) { $source = if ($entry.ContainsKey('Splash') -and $entry.Splash) { $splashSource } else { $iconSource } $outputPath = Join-Path $resolvedAssetsDirectory $entry.Name Save-PngVariant -Source $source -OutputPath $outputPath -Width $entry.Width -Height $entry.Height -Mode $entry.Mode Write-Host ("Generated {0} ({1}x{2})" -f $entry.Name, $entry.Width, $entry.Height) -ForegroundColor Cyan } } finally { $iconSource.Dispose() $splashSource.Dispose() } if (-not $SkipValidation) { $validatorScript = Join-Path $PSScriptRoot 'Test-TechShellManifestAssets.ps1' if (-not (Test-Path -LiteralPath $validatorScript -PathType Leaf)) { throw "Validator script not found: $validatorScript" } & $validatorScript } Write-Host "TechShell asset generation completed." -ForegroundColor Green # SIG # Begin signature block # MIIcLwYJKoZIhvcNAQcCoIIcIDCCHBwCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCrxQmKXNojiL23 # X7UBb4EdgKsFfK1QOchmrxzvwIxdoqCCFmgwggMqMIICEqADAgECAhAUclYcLlB0 # o0+hlxGb32/OMA0GCSqGSIb3DQEBCwUAMC0xKzApBgNVBAMMIlRlY2hUb29sYm94 # IFRlY2hTaGVsbCBDb2RlIFNpZ25pbmcwHhcNMjYxMDAzMDE0MjMyWhcNMjgxMDAz # MDE1MjMxWjAtMSswKQYDVQQDDCJUZWNoVG9vbGJveCBUZWNoU2hlbGwgQ29kZSBT # aWduaW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApXcCV9CPSwPJ # 42duP85fSh0jCkJWIov+AYymeKQzBLgsz6jCkhuuKBf7gpsStULwAJuBtFztT/XI # 0jK0e+3SIzYCaG+1nn0rzBsB4YisBtMykS+EtRgmjcu2h1YMGiQ/FScDak5h707Z # hQ/VBXZ/+rZ7Wd08wUnWHAsNRz75wz/kiWGEoCDIuLsl4uy+gQmXlQVBFn8ALEh0 # AtJk0B7c6qzz1y0So8y4Lq1IXvCEnN61HYSJ5zaopOMvNo3pNsrr0sM7m9DyEzu4 # Ci3EWtuyXbPegoV62qC62MRllrFJNzV6dJBUuXqCAhgMFGaT6Mj2/qRlBiVVmTFe # FXTX9pHvxQIDAQABo0YwRDAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYB # BQUHAwMwHQYDVR0OBBYEFB8+5HahBP9rHFC1mG3OWbTh3WwxMA0GCSqGSIb3DQEB # CwUAA4IBAQAOdqNp/5ce+dpVcp2FivGK7FpYroSWaeOoEDEDLnxq58mDEZKBwfYM # SduDQ4AHZQ3U1WRrvHWyiPpFI5lOt1utiw9WHrA4sHuvxGmFkcfH4J8AsRtlVK94 # yUX16UZhLPXWItGM75rUz/uRSBcyXQWOzq5gfwNL22F5Z8AljAicEBAZLUhuQBpd # 9rE3JWZ0rZzbRZNd4Hb4/DP53KaiA7zfZyXmuEfLCCwyGtcPn3Mqxu6IsCU8LmzH # 2fClU7OGxte+VxaczuFaPqmIBtChvxj4ZoluHWgWOIXqyOsSc9v9qzYeHM6i4pY4 # pRkjpGU/2NWfwVbOkyJxQlE9XdhO3IXGMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv # 21DiCEAYWjANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQD # ExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcN # MzExMTA5MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQg # SW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2Vy # dCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC # AQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf # 8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1 # mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe # 7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecx # y9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX # 2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX # 9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp49 # 3ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCq # sWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH # dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauG # i0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYw # DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08w # HwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGG # MHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl # cnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v # RGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0 # dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5j # cmwwEQYDVR0gBAowCDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXn # OF+go3QbPbYW1/e/Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23 # OO/0/4C5+KH38nLeJLxSA8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFI # tJnLnU+nBgMTdydE1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7s # pNU96LHc/RzY9HdaXFSMb++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgi # wbJZ9VVrzyerbHbObyMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cB # qZ9Xql4o4rmUMIIGtDCCBJygAwIBAgIQDcesVwX/IZkuQEMiDDpJhjANBgkqhkiG # 9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw # FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVz # dGVkIFJvb3QgRzQwHhcNMjUwNTA3MDAwMDAwWhcNMzgwMTE0MjM1OTU5WjBpMQsw # CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERp # Z2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIw # MjUgQ0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtHgx0wqYQXK+ # PEbAHKx126NGaHS0URedTa2NDZS1mZaDLFTtQ2oRjzUXMmxCqvkbsDpz4aH+qbxe # Lho8I6jY3xL1IusLopuW2qftJYJaDNs1+JH7Z+QdSKWM06qchUP+AbdJgMQB3h2D # Z0Mal5kYp77jYMVQXSZH++0trj6Ao+xh/AS7sQRuQL37QXbDhAktVJMQbzIBHYJB # YgzWIjk8eDrYhXDEpKk7RdoX0M980EpLtlrNyHw0Xm+nt5pnYJU3Gmq6bNMI1I7G # b5IBZK4ivbVCiZv7PNBYqHEpNVWC2ZQ8BbfnFRQVESYOszFI2Wv82wnJRfN20VRS # 3hpLgIR4hjzL0hpoYGk81coWJ+KdPvMvaB0WkE/2qHxJ0ucS638ZxqU14lDnki7C # coKCz6eum5A19WZQHkqUJfdkDjHkccpL6uoG8pbF0LJAQQZxst7VvwDDjAmSFTUm # s+wV/FbWBqi7fTJnjq3hj0XbQcd8hjj/q8d6ylgxCZSKi17yVp2NL+cnT6Toy+rN # +nM8M7LnLqCrO2JP3oW//1sfuZDKiDEb1AQ8es9Xr/u6bDTnYCTKIsDq1BtmXUqE # G1NqzJKS4kOmxkYp2WyODi7vQTCBZtVFJfVZ3j7OgWmnhFr4yUozZtqgPrHRVHhG # NKlYzyjlroPxul+bgIspzOwbtmsgY1MCAwEAAaOCAV0wggFZMBIGA1UdEwEB/wQI # MAYBAf8CAQAwHQYDVR0OBBYEFO9vU0rp5AZ8esrikFb2L9RJ7MtOMB8GA1UdIwQY # MBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUE # DDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6 # Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMu # ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDww # OjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3Rl # ZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMA0G # CSqGSIb3DQEBCwUAA4ICAQAXzvsWgBz+Bz0RdnEwvb4LyLU0pn/N0IfFiBowf0/D # m1wGc/Do7oVMY2mhXZXjDNJQa8j00DNqhCT3t+s8G0iP5kvN2n7Jd2E4/iEIUBO4 # 1P5F448rSYJ59Ib61eoalhnd6ywFLerycvZTAz40y8S4F3/a+Z1jEMK/DMm/axFS # goR8n6c3nuZB9BfBwAQYK9FHaoq2e26MHvVY9gCDA/JYsq7pGdogP8HRtrYfctSL # ANEBfHU16r3J05qX3kId+ZOczgj5kjatVB+NdADVZKON/gnZruMvNYY2o1f4MXRJ # DMdTSlOLh0HCn2cQLwQCqjFbqrXuvTPSegOOzr4EWj7PtspIHBldNE2K9i697cva # iIo2p61Ed2p8xMJb82Yosn0z4y25xUbI7GIN/TpVfHIqQ6Ku/qjTY6hc3hsXMrS+ # U0yy+GWqAXam4ToWd2UQ1KYT70kZjE4YtL8Pbzg0c1ugMZyZZd/BdHLiRu7hAWE6 # bTEm4XYRkA6Tl4KSFLFk43esaUeqGkH/wyW4N7OigizwJWeukcyIPbAvjSabnf7+ # Pu0VrFgoiovRDiyx3zEdmcif/sYQsfch28bZeUz2rtY/9TCA6TD8dC3JE3rYkrhL # ULy7Dc90G6e8BlqmyIjlgp2+VqsS9/wQD7yFylIz0scmbKvFoW2jNrbM1pD2T7m3 # XDCCBu0wggTVoAMCAQICEAhP3DNPfkVO28MPj/mSGDUwDQYJKoZIhvcNAQELBQAw # aTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQD # EzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBSU0E0MDk2IFNIQTI1 # NiAyMDI1IENBMTAeFw0yNjA4MDUwMDAwMDBaFw0zNzExMDQyMzU5NTlaMGMxCzAJ # BgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGln # aUNlcnQgU0hBMjU2IFJTQTQwOTYgVGltZXN0YW1wIFJlc3BvbmRlciAyMDI2IDEw # ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2e6byyf7NSvjUm0xls/04 # xjD4fAkOkbnGQi7+Wpx81iYxfzViaxSIctuH3KSl5YEYpMuFgGsA31N2D9ATMbfZ # dw5uaAhuWevQKhDdZIB4NnqcfpfpWQXJiQnDdAElETC+bhSEvNLGbA8DtwUpFMQ4 # yyYQSPqomT92osQAv6hBi47ATZS6JfVWe6XxhF4jJZ3iSAuf2Cros1czRSmWRHqM # v9AfGZvp8ygYElhudpQjtcPpwoOl6QrZJUyV3iINvN4cO05prGV0fkjG426xDr2d # 3z9lcSIHkdvGPdGUrXdxfVbgOUVcp2/8ISEzwKPW++Wa+E2ujI91EZtukGWDJ/xZ # 27k3oHKEXBRGfRTqjOU+jE3ba/5++JSE/7oNHnjs5mekExYN96LV/mxUbCKJb8pB # NY4r3uD7hEmk/M81XhVgwDA7aMzYC3LZBg9WY5BMmbSay5ecmtJuXaB/0nKWmQmV # ZeqTVDgsmzHP5MQuhAJkiWNuC9MmCg9TZHXbJ2/yLVSov9p16UDTLtT0+aa1vN71 # fHeu1qMLlLNB3WOB/ADCxr3S/1hxI92Z6jKgEED/btwIvbfuXkNNhg8MtDg43c4t # MZae9FvqMOt/9PvmAxF9TNIsIFB8G6yb36ZJZGUL8N/pL971DyLXcK6HM5PYnH5X # +eVtczhCgHCVQCF6XDAlPQIDAQABo4IBlTCCAZEwDAYDVR0TAQH/BAIwADAdBgNV # HQ4EFgQUFMljijAu1Er7bpTz5uNAfvXszeIwHwYDVR0jBBgwFoAU729TSunkBnx6 # yuKQVvYv1Ensy04wDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsGAQUF # BwMIMIGVBggrBgEFBQcBAQSBiDCBhTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au # ZGlnaWNlcnQuY29tMF0GCCsGAQUFBzAChlFodHRwOi8vY2FjZXJ0cy5kaWdpY2Vy # dC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2U0hBMjU2 # MjAyNUNBMS5jcnQwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDovL2NybDMuZGlnaWNl # cnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGltZVN0YW1waW5nUlNBNDA5NlNIQTI1 # NjIwMjVDQTEuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATAN # BgkqhkiG9w0BAQsFAAOCAgEAjcU6YR6dUgrfmawJgH59KECxa9Ji8sEi2g10CBDa # MiqsaxWyW5cwlT/6ZF5sFznazqVsoC85U9dqLOYqQwst+UQQoNlDHgKRLa3xoc+O # ReFreFhnTXSG0Vrd2E2CZqUfm+5a+He1MJ/h+tNLuA+0Zzhn/Fo+FDYAHWZHx4R7 # 9ZsfRFYe9UiXpXBDf6DkUo183Y38NYmR/XfDYf7YZ+oR9t3flbDwK+hgGMs0gNNp # 1w9Z2CyOyI5or/sSwomAuNQ0hWC9xoU4stD8aWsD7RkcmgVRs6vlIk3zPKQ+ylch # eWkMlj+CoVRlFE55pv0ZWCaFt04lwP/rdGHE9qEVQZtyRE42ox7oNgC/r+Y4bSlZ # 3dw9K2x1xLtu6PkPKeLBFjzKigwfqm3Hm+k/+lnME8F5kPZTgiy2HLEHklpryqs6 # QHnPXrRNeIzkAMyylnRN8P0wmirS0WkU+ywpEWFZ4QNg+9xS43tTuW9x0eXh7NDc # 1P/sV+zWxHXKH8tFt1ncHdVzqrZaYPyYMLSn2TOXajveJW1L3joiQSPsWRGxkbDD # W15jERFE4LvjnGu2O9zD1nLJSMdlYZEikl4w2w+q4IN/R+TIe0H4ngCI1moJCTbe # vGH4punIxM1Uoi0nmX3ZK+XbRT01uowE5ViXWHng0RgsmrX/EdYUo80r3TfMlkD0 # /YMxggUdMIIFGQIBATBBMC0xKzApBgNVBAMMIlRlY2hUb29sYm94IFRlY2hTaGVs # bCBDb2RlIFNpZ25pbmcCEBRyVhwuUHSjT6GXEZvfb84wDQYJYIZIAWUDBAIBBQCg # gYQwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYB # BAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0B # CQQxIgQghS1dTvw8XPf9qqDl3g5IPzDQj6ul5PS5iOSaT6NXkcUwDQYJKoZIhvcN # AQEBBQAEggEAoVlu6YXiphgauXiePzqsLxJ0p02HQX3HxbJBCCeV5gVzgwOkS7UQ # PJmvxBHlzlv2jN4B/NBNWlevaVv3gQMToJlglx1oOLqDV6g1I3QC5OANWQMcKwqO # dAnGVGKlnqqbl99DWG1mfqZBeNFNLMe5/AKXg3X6tYDmag5TTUdg4tUmTaUgECR+ # F3HxuRBdWkEnObC6BgvDRfj0/AnruOiadn3ToyLRSzCEM/8ER3CmJ0dZ+ZxdoOdU # RKszWT1cnkch7GfUgYq+/PBSa+Eqkw7wcS82wsmeuxL/wWUJl2C+NIWHMFTMC0xd # EwTTD9Kxg2SRfxCMbWH13c/DEJxsdEaJ3KGCAyYwggMiBgkqhkiG9w0BCQYxggMT # MIIDDwIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5j # LjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNB # NDA5NiBTSEEyNTYgMjAyNSBDQTECEAhP3DNPfkVO28MPj/mSGDUwDQYJYIZIAWUD # BAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEP # Fw0yNjEwMDMyMDQwNDRaMC8GCSqGSIb3DQEJBDEiBCAxKyQZZXt1pJ6trEVlhY4I # urbR3bHrbHxVOaGtLFZc5DANBgkqhkiG9w0BAQEFAASCAgC1nKWbQWJPsk647Z70 # q8GwSJIsziAE9mZiAxHAiAlmoV7ZPEyCKTkDvOt10eETYCn2Eebnf35HqWT4yypx # +350hPwvVcM1LlNWyg6Lqkkpd6MtPt9u6vS/2LhAuaqRpGghmen6N017EA3xbayt # CyAii5VQm9Px3nQrPlQCrnvVGUuXgSzqSTZoGmCUmn3DB8G228MG2YwtMTyMOIVA # enOuf2oOOALj0lotyglrIrhhGCmo3CEJ8gvVIhFAt02o9de+1Ou+SEFCoBAHcdhp # +w2l5ChXEDCP/CgPqVINsqQgGT35KxJHBaaU7ExUow4T0UgruKd7PdE+tK4UO4SZ # xaYtxU2iE6E7nEUF+asLg0/m7uArxbw1JIkcdAZUevo4z+0+CRaPxTAwOQLZsjD5 # LtKsDLBvxnem5jSFuGwPTb49DQZTj8b5PjbkjNtRqW06r8Oflc/6pz44nkf2vtjQ # /Xx87Z9rUrJ7ESgTUMNfYi1RXWSd5W8EUgof7jXRq5YLJLQorGp9wUxP0Kw41IAn # iyOH0RG70hECLzfNDyhpbfTnJ8NH8RnopxSuFoAUU+2ioevVUj69N2C3TFosJMdH # cI5HnqYFsnl+YEmrGYJR9xhmq2+Z52tZE/HLiH97GfIIL8EMatRg2xKCg15BVUat # Rh6KM1tGomTW8n6NFz5wd3JOHw== # SIG # End signature block |