ImagePlayground.psm1
$LibraryName = 'ImagePlayground.PowerShell' $Library = "$LibraryName.dll" $Class = "$LibraryName.Initialize" $AssemblyFolders = Get-ChildItem -Path $PSScriptRoot\Lib -Directory -ErrorAction SilentlyContinue $Default = $false $Core = $false $Standard = $false foreach ($A in $AssemblyFolders.Name) { if ($A -eq 'Default') { $Default = $true } elseif ($A -eq 'Core') { $Core = $true } elseif ($A -eq 'Standard') { $Standard = $true } } if ($Standard -and $Core -and $Default) { $FrameworkNet = 'Default' $Framework = 'Standard' } elseif ($Standard -and $Core) { $Framework = 'Standard' $FrameworkNet = 'Standard' } elseif ($Core -and $Default) { $Framework = 'Core' $FrameworkNet = 'Default' } elseif ($Standard -and $Default) { $Framework = 'Standard' $FrameworkNet = 'Default' } elseif ($Standard) { $Framework = 'Standard' $FrameworkNet = 'Standard' } elseif ($Core) { $Framework = 'Core' $FrameworkNet = '' } elseif ($Default) { $Framework = '' $FrameworkNet = 'Default' } else { Write-Error -Message 'No assemblies found' } if ($PSEdition -eq 'Core') { $LibFolder = $Framework } else { $LibFolder = $FrameworkNet } try { $ImportModule = Get-Command -Name Import-Module -Module Microsoft.PowerShell.Core if (-not ($Class -as [type])) { & $ImportModule ([IO.Path]::Combine($PSScriptRoot, 'Lib', $LibFolder, $Library)) -ErrorAction Stop } else { $Type = "$Class" -as [Type] & $importModule -Force -Assembly ($Type.Assembly) } } catch { Write-Warning -Message "Importing module $Library failed. Fix errors before continuing. Error: $($_.Exception.Message)" $true } . $PSScriptRoot\ImagePlayground.Libraries.ps1 function ConvertTo-Image { <# .SYNOPSIS Converts the image to the specified format. .DESCRIPTION Converts the image to the specified format. The output path must include the file extension. .PARAMETER FilePath File path to the image you want to convert. .PARAMETER OutputPath File path to the output image that will be created. .EXAMPLE ConvertTo-Image -FilePath $PSScriptRoot\Samples\LogoEvotec.png -OutputPath $PSScriptRoot\Output\LogoEvotec.jpg .NOTES General notes #> [cmdletBinding()] param([parameter(Mandatory)][string] $FilePath, [parameter(Mandatory)][string] $OutputPath) if ($FilePath -and (Test-Path -LiteralPath $FilePath)) { [ImagePlayground.ImageHelper]::ConvertTo($FilePath, $OutputPath) } else { Write-Warning -Message "Resize-Image - File $FilePath not found. Please check the path." } } function Get-Image { <# .SYNOPSIS Gets the image from the file path for further processing and image manipulation. .DESCRIPTION Gets the image from the file path for further processing and image manipulation. .PARAMETER FilePath File path to the image you want to read and manipulate. .EXAMPLE $Image = Get-Image -FilePath $PSScriptRoot\Samples\LogoEvotec.png $Image.BlackWhite() $Image.BackgroundColor("Red") Save-Image -Image $Image -Open -FilePath $PSScriptRoot\Output\LogoEvotecChanged.png .NOTES General notes #> [CmdletBinding()] param([string] $FilePath) if (-not (Test-Path -LiteralPath $FilePath)) { Write-Warning -Message "Get-Image - File $FilePath not found. Please check the path." return } $Image = [ImagePlayground.Image]::Load($FilePath) $Image } function Get-ImageBarCode { [cmdletBinding()] param([string] $FilePath) if ($FilePath -and (Test-Path -LiteralPath $FilePath)) { $BarCode = [ImagePlayground.BarCode]::Read($FilePath) $BarCode } else { Write-Warning -Message "Get-ImageBarCode - File $FilePath not found. Please check the path." } } function Get-ImageQRCode { [cmdletBinding()] param([string] $FilePath) if ($FilePath -and (Test-Path -LiteralPath $FilePath)) { $QRCode = [ImagePlayground.QRCode]::Read($FilePath) $QRCode } else { Write-Warning -Message "Get-ImageQRCode - File $FilePath not found. Please check the path." } } function Merge-Image { [CmdletBinding()] param([string] $FilePath, [string] $FilePathToMerge, [string] $FilePathOutput, [switch] $ResizeToFit, [ImagePlayground.ImagePlacement] $Placement = [ImagePlayground.ImagePlacement]::Bottom) if (-not (Test-Path -LiteralPath $FilePath)) { Write-Warning -Message "Merge-Image - File $FilePath not found. Please check the path." return } if (-not (Test-Path -LiteralPath $FilePathToMerge)) { Write-Warning -Message "Merge-Image - File $FilePathToMerge not found. Please check the path." return } [ImagePlayground.ImageHelper]::Combine($FilePath, $FilePathToMerge, $FilePathOutput, $ResizeToFit.IsPresent, $Placement) } function New-ImageBarCode { [cmdletBinding()] param([parameter(Mandatory)][ImagePlayground.BarCode+BarcodeTypes] $Type, [parameter(Mandatory)][string] $Value, [parameter(Mandatory)][string] $FilePath) [ImagePlayground.BarCode]::Generate($Type, $Value, $filePath) } function New-ImageChart { [cmdletBinding()] param([scriptblock] $ChartsDefinition, [int] $Width = 600, [int] $Height = 400, [string] $FilePath, [switch] $Show) $ValueHash = [ordered] @{} $Values = [System.Collections.Generic.List[double]]::new() $Labels = [System.Collections.Generic.List[string]]::new() $Positions = [System.Collections.Generic.List[int]]::new() $Plot = [ScottPlot.Plot]::new($Width, $Height) $Position = 0 if ($ChartsDefinition) { $OutputDefintion = & $ChartsDefinition foreach ($Definition in $OutputDefintion) { if ($Definition.ObjectType -eq 'Bar') { $Type = 'Bar' for ($i = 0; $i -lt $Definition.Value.Count; $i++) { if (-not $ValueHash["$i"]) { $ValueHash["$i"] = [System.Collections.Generic.List[double]]::new() } $ValueHash["$i"].Add($Definition.Value[$i]) } $Labels.Add($Definition.Name) } elseif ($Definition.ObjectType -eq 'Line') { $Type = 'Line' $ValueHash["$($Definition.Name)"] = $Definition.Value } elseif ($Definition.ObjectType -eq 'Pie') { $Type = 'Pie' $Values.Add($Definition.Value) $Labels.Add($Definition.Name) } $Positions.Add($Position) $Position++ } } if ($Type -eq 'Bar') { if ($ValueHash) { foreach ($Value in $ValueHash.Keys) { $null = $Plot.AddBar($ValueHash[$Value]) } } if ($Labels) { $null = $Plot.XTicks($Positions, $Labels) } } elseif ($Type -eq 'Line') { if ($ValueHash) { foreach ($Value in $ValueHash.Keys) { $null = $Plot.AddSignal($ValueHash[$Value], 1, $null, $Value) } } $null = $Plot.Legend($true, 7) } elseif ($Type -eq 'Pie') { $PieChart = $Plot.AddPie($Values) $PieChart.SliceLabels = $Labels $PieChart.ShowLabels = $true } if (-not $FilePath) { $FilePath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "$($([System.IO.Path]::GetRandomFileName()).Split('.')[0]).png") Write-Warning -Message "New-ImageChart - No file path specified, saving to $FilePath" } try { $null = $Plot.SaveFig($FilePath) if ($Show) { Invoke-Item -LiteralPath $FilePath } } catch { Write-Warning -Message "New-ImageChart - Error creating image chart $($_.Exception.Message)" } } function New-ImageChartBar { [cmdletBinding()] param([alias('Label')][string] $Name, [Array] $Value) [PSCustomObject] @{ObjectType = 'Bar' Name = $Name Value = $Value } } function New-ImageChartBarOptions { [cmdletBinding()] param([switch] $ShowValuesAboveBars) [PSCustomObject] @{ObjectType = 'BarOptions' ShowValuesAboveBars = $ShowValuesAboveBars.IsPresent } } function New-ChartLegend { param() } function New-ImageChartLine { [CmdletBinding()] param([alias('Label')][string] $Name, [Array] $Value) [PSCustomObject] @{ObjectType = 'Line' Name = $Name Value = $Value } } function New-ImageChartPie { [cmdletbinding()] param([alias('Label')][string] $Name, [double] $Value) [PSCustomObject] @{ObjectType = 'Pie' Name = $Name Value = $Value } } function New-ImageQRCode { [Alias('New-QRCode')] [cmdletBinding()] param([Parameter(Mandatory)][string] $Content, [Parameter(Mandatory)][string] $FilePath) if (-not $FilePath) { $FilePath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "$($([System.IO.Path]::GetRandomFileName()).Split('.')[0]).png") Write-Warning -Message "New-ImageQRCode - No file path specified, saving to $FilePath" } try { [ImagePlayground.QrCode]::Generate($Content, $FilePath, $false) if ($Show) { Invoke-Item -LiteralPath $FilePath } } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "New-ImageQRCodeWiFi - Error creating image $($_.Exception.Message)" } } } function New-ImageQRCodeWiFi { [alias('New-QRCodeWiFi')] [cmdletBinding()] param([Parameter(Mandatory)][string] $SSID, [Parameter(Mandatory)][string] $Password, [Parameter(Mandatory)][string] $FilePath, [switch] $Show) if (-not $FilePath) { $FilePath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "$($([System.IO.Path]::GetRandomFileName()).Split('.')[0]).png") Write-Warning -Message "New-ImageQRCodeWiFi - No file path specified, saving to $FilePath" } try { [ImagePlayground.QrCode]::GenerateWiFi($ssid, $password, $FilePath, $false) if ($Show) { Invoke-Item -LiteralPath $FilePath } } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "New-ImageQRCodeWiFi - Error creating image $($_.Exception.Message)" } } } function New-ImageQRContact { [cmdletBinding()] param([Parameter(Mandatory)][string] $FilePath, [QRCoder.PayloadGenerator+ContactData+ContactOutputType] $outputType = [QRCoder.PayloadGenerator+ContactData+ContactOutputType]::VCard4, [string] $Firstname, [string] $Lastname, [string] $Nickname , [string] $Phone , [string] $MobilePhone , [string] $WorkPhone , [string] $Email , [DateTime] $Birthday , [string] $Website , [string] $Street , [string] $HouseNumber , [string] $City , [string] $ZipCode , [string] $Country , [string] $Note , [string] $StateRegion , [ValidateSet('Default', 'Reversed')][string] $AddressOrder = 'Default', [string] $Org , [string] $OrgTitle, [switch] $Show) if (-not $FilePath) { $FilePath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "$($([System.IO.Path]::GetRandomFileName()).Split('.')[0]).png") Write-Warning -Message "New-ImageQRContact - No file path specified, saving to $FilePath" } try { [ImagePlayground.QrCode]::GenerateContact($filePath, $outputType, $firstname, $lastname, $nickname, $phone, $mobilePhone, $workPhone, $email, $birthday, $website, $street, $houseNumber, $city, $zipCode, $country, $note, $stateRegion, $addressOrder, $org, $orgTitle, $false) if ($Show) { Invoke-Item -LiteralPath $FilePath } } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "New-ImageQRContact - Error creating image $($_.Exception.Message)" } } } function Resize-Image { <# .SYNOPSIS Resizes the image to given width and height or percentage. .DESCRIPTION Resizes the image to given width and height or percentage. By default it will respect aspect ratio. If you want to ignore it use -DontRespectAspectRatio switch. This means you can only provide Width and the height will be automatically calculated or vice versa. You can also use percentage to resize the image maintaining the aspect ratio. .PARAMETER FilePath File path to the image you want to resize .PARAMETER OutputPath File path to the output image that will be created .PARAMETER Width New width of the image .PARAMETER Height New height of the image .PARAMETER Percentage Percentage of the image to resize .PARAMETER DontRespectAspectRatio If you want to ignore aspect ratio use this switch. It only affects Width and Height parameters that are used separately. .EXAMPLE Resize-Image -FilePath $PSScriptRoot\Samples\LogoEvotec.png -OutputPath $PSScriptRoot\Output\LogoEvotecResize.png -Width 100 -Height 100 .EXAMPLE Resize-Image -FilePath $PSScriptRoot\Samples\LogoEvotec.png -OutputPath $PSScriptRoot\Output\LogoEvotecResizeMaintainAspectRatio.png -Width 300 .EXAMPLE Resize-Image -FilePath $PSScriptRoot\Samples\LogoEvotec.png -OutputPath $PSScriptRoot\Output\LogoEvotecResizePercent.png -Percentage 200 .NOTES General notes #> [cmdletBinding(DefaultParameterSetName = 'HeightWidth')] param([parameter(ParameterSetName = 'Percentage')] [parameter(ParameterSetName = 'HeightWidth')] [parameter(Mandatory)][string] $FilePath, [parameter(ParameterSetName = 'Percentage')] [parameter(ParameterSetName = 'HeightWidth')] [parameter(Mandatory)][string] $OutputPath, [parameter(ParameterSetName = 'HeightWidth')][int] $Width, [parameter(ParameterSetName = 'HeightWidth')][int] $Height, [parameter(ParameterSetName = 'Percentage')][int] $Percentage, [parameter(ParameterSetName = 'HeightWidth')][switch] $DontRespectAspectRatio) if ($FilePath -and (Test-Path -LiteralPath $FilePath)) { if ($Percentage) { [ImagePlayground.ImageHelper]::Resize($FilePath, $OutputPath, $Percentage) } else { if ($DontRespectAspectRatio) { if ($PSBoundParameters.ContainsKey('Width') -and $PSBoundParameters.ContainsKey('Height')) { [ImagePlayground.ImageHelper]::Resize($FilePath, $OutputPath, $Width, $Height) } elseif ($PSBoundParameters.ContainsKey('Width')) { [ImagePlayground.ImageHelper]::Resize($FilePath, $OutputPath, $Width, $null, $false) } elseif ($PSBoundParameters.ContainsKey('Height')) { [ImagePlayground.ImageHelper]::Resize($FilePath, $OutputPath, $null, $Height, $false) } else { Write-Warning -Message "Resize-Image - Please specify Width or Height or Percentage." } } else { if ($PSBoundParameters.ContainsKey('Width') -and $PSBoundParameters.ContainsKey('Height')) { [ImagePlayground.ImageHelper]::Resize($FilePath, $OutputPath, $Width, $Height) } elseif ($PSBoundParameters.ContainsKey('Width')) { [ImagePlayground.ImageHelper]::Resize($FilePath, $OutputPath, $Width, $null) } elseif ($PSBoundParameters.ContainsKey('Height')) { [ImagePlayground.ImageHelper]::Resize($FilePath, $OutputPath, $null, $Height) } else { Write-Warning -Message "Resize-Image - Please specify Width or Height or Percentage." } } } } else { Write-Warning -Message "Resize-Image - File $FilePath not found. Please check the path." } } function Save-Image { [cmdletBinding()] param([parameter(Mandatory)][ImagePlayground.Image] $Image, [string] $FilePath, [switch] $Open) if ($FilePath) { $Image.Save($FilePath, $Open.IsPresent) } else { $Image.Save($Open.IsPresent) } } if ($PSVersionTable.PSEdition -eq 'Desktop' -and (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full").Release -lt 461808) { Write-Warning "This module requires .NET Framework 4.7.2 or later."; return } Export-ModuleMember -Function @('ConvertTo-Image', 'Get-Image', 'Get-ImageBarCode', 'Get-ImageQRCode', 'Merge-Image', 'New-ChartLegend', 'New-ImageBarCode', 'New-ImageChart', 'New-ImageChartBar', 'New-ImageChartBarOptions', 'New-ImageChartLine', 'New-ImageChartPie', 'New-ImageQRCode', 'New-ImageQRCodeWiFi', 'New-ImageQRContact', 'Resize-Image', 'Save-Image') -Alias @('New-QRCode', 'New-QRCodeWiFi') # SIG # Begin signature block # MIInPgYJKoZIhvcNAQcCoIInLzCCJysCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCwtA7b1gLSnYBZ # u5Gw6NrfT1mOvTOGrxh7EJwoM2nfLKCCITcwggO3MIICn6ADAgECAhAM5+DlF9hG # /o/lYPwb8DA5MA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBa # Fw0zMTExMTAwMDAwMDBaMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lD # ZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC # AQoCggEBAK0OFc7kQ4BcsYfzt2D5cRKlrtwmlIiq9M71IDkoWGAM+IDaqRWVMmE8 # tbEohIqK3J8KDIMXeo+QrIrneVNcMYQq9g+YMjZ2zN7dPKii72r7IfJSYd+fINcf # 4rHZ/hhk0hJbX/lYGDW8R82hNvlrf9SwOD7BG8OMM9nYLxj+KA+zp4PWw25EwGE1 # lhb+WZyLdm3X8aJLDSv/C3LanmDQjpA1xnhVhyChz+VtCshJfDGYM2wi6YfQMlqi # uhOCEe05F52ZOnKh5vqk2dUXMXWuhX0irj8BRob2KHnIsdrkVxfEfhwOsLSSplaz # vbKX7aqn8LfFqD+VFtD/oZbrCF8Yd08CAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGG # MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEXroq/0ksuCMS1Ri6enIZ3zbcgP # MB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBBQUA # A4IBAQCiDrzf4u3w43JzemSUv/dyZtgy5EJ1Yq6H6/LV2d5Ws5/MzhQouQ2XYFwS # TFjk0z2DSUVYlzVpGqhH6lbGeasS2GeBhN9/CTyU5rgmLCC9PbMoifdf/yLil4Qf # 6WXvh+DfwWdJs13rsgkq6ybteL59PyvztyY1bV+JAbZJW58BBZurPSXBzLZ/wvFv # hsb6ZGjrgS2U60K3+owe3WLxvlBnt2y98/Efaww2BxZ/N3ypW2168RJGYIPXJwS+ # S86XvsNnKmgR34DnDDNmvxMNFG7zfx9jEB76jRslbWyPpbdhAbHSoyahEHGdreLD # +cOZUbcrBwjOLuZQsqf6CkUvovDyMIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1U0O1 # b5VQCDANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln # aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtE # aWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcNMjgx # MDIyMTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j # MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBT # SEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEF # AAOCAQ8AMIIBCgKCAQEA+NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid2zLX # cep2nQUut4/6kkPApfmJ1DcZ17aq8JyGpdglrA55KDp+6dFn08b7KSfH03sjlOSR # I5aQd4L5oYQjZhJUM1B0sSgmuyRpwsJS8hRniolF1C2ho+mILCCVrhxKhwjfDPXi # TWAYvqrEsq5wMWYzcT6scKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzLfnQ5 # Ng2Q7+S1TqSp6moKq4TzrGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR93O8 # vYWxYoNzQYIH5DiLanMg0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckwEgYD # VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYB # BQUHAwMweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k # aWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0 # LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4 # oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJv # b3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy # dEFzc3VyZWRJRFJvb3RDQS5jcmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCow # KAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZI # AYb9bAMwHQYDVR0OBBYEFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQYMBaA # FEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1aJLPz # ItEVyCx8JSl2qB1dHC06GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew4fbRknUPUbRu # pY5a4l4kgU4QpO4/cY5jDhNLrddfRHnzNhQGivecRk5c/5CxGwcOkRX7uq+1UcKN # JK4kxscnKqEpKBo6cSgCPC6Ro8AlEeKcFEehemhor5unXCBc2XGxDI+7qPjFEmif # z0DLQESlE/DmZAwlCEIysjaKJAL+L3J+HNdJRZboWR3p+nRka7LrZkPas7CM1ekN # 3fYBIM6ZMWM9CBoYs4GbT8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhsRDKy # ZqHnGKSaZFHvMIIFPTCCBCWgAwIBAgIQBNXcH0jqydhSALrNmpsqpzANBgkqhkiG # 9w0BAQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw # FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEy # IEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTIwMDYyNjAwMDAwMFoXDTIz # MDcwNzEyMDAwMFowejELMAkGA1UEBhMCUEwxEjAQBgNVBAgMCcWabMSFc2tpZTER # MA8GA1UEBxMIS2F0b3dpY2UxITAfBgNVBAoMGFByemVteXPFgmF3IEvFgnlzIEVW # T1RFQzEhMB8GA1UEAwwYUHJ6ZW15c8WCYXcgS8WCeXMgRVZPVEVDMIIBIjANBgkq # hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7KB3iyBrhkLUbbFe9qxhKKPBYqDBqln # r3AtpZplkiVjpi9dMZCchSeT5ODsShPuZCIxJp5I86uf8ibo3vi2S9F9AlfFjVye # 3dTz/9TmCuGH8JQt13ozf9niHecwKrstDVhVprgxi5v0XxY51c7zgMA2g1Ub+3ti # i0vi/OpmKXdL2keNqJ2neQ5cYly/GsI8CREUEq9SZijbdA8VrRF3SoDdsWGf3tZZ # zO6nWn3TLYKQ5/bw5U445u/V80QSoykszHRivTj+H4s8ABiforhi0i76beA6Ea41 # zcH4zJuAp48B4UhjgRDNuq8IzLWK4dlvqrqCBHKqsnrF6BmBrv+BXQIDAQABo4IB # xTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYE # FBixNSfoHFAgJk4JkDQLFLRNlJRmMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK # BggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdpY2Vy # dC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2NybDQu # ZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3 # BglghkgBhv1sAwEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu # Y29tL0NQUzAIBgZngQwBBAEwgYQGCCsGAQUFBwEBBHgwdjAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME4GCCsGAQUFBzAChkJodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyQXNzdXJlZElEQ29kZVNpZ25p # bmdDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAmr1sz4ls # LARi4wG1eg0B8fVJFowtect7SnJUrp6XRnUG0/GI1wXiLIeow1UPiI6uDMsRXPHU # F/+xjJw8SfIbwava2eXu7UoZKNh6dfgshcJmo0QNAJ5PIyy02/3fXjbUREHINrTC # vPVbPmV6kx4Kpd7KJrCo7ED18H/XTqWJHXa8va3MYLrbJetXpaEPpb6zk+l8Rj9y # G4jBVRhenUBUUj3CLaWDSBpOA/+sx8/XB9W9opYfYGb+1TmbCkhUg7TB3gD6o6ES # Jre+fcnZnPVAPESmstwsT17caZ0bn7zETKlNHbc1q+Em9kyBjaQRcEQoQQNpezQu # g9ufqExx6lHYDjCCBY0wggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZI # hvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ # MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNz # dXJlZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVow # YjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ # d3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290 # IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjww # IjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J5 # 8soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMH # hOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6 # Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQ # ecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4b # A3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9 # WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCU # tNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvo # ZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/J # vNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCP # orF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMB # Af8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXr # oq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRt # MGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEF # BQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl # ZElEUm9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgw # BgYEVR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cH # vZqsoYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8 # UgPITtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTn # f+hZqPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxU # jG/voVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8j # LfR+cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDCCBq4w # ggSWoAMCAQICEAc2N7ckVHzYR6z9KGYqXlswDQYJKoZIhvcNAQELBQAwYjELMAkG # A1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRp # Z2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4X # DTIyMDMyMzAwMDAwMFoXDTM3MDMyMjIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAV # BgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVk # IEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTCCAiIwDQYJKoZIhvcN # AQEBBQADggIPADCCAgoCggIBAMaGNQZJs8E9cklRVcclA8TykTepl1Gh1tKD0Z5M # om2gsMyD+Vr2EaFEFUJfpIjzaPp985yJC3+dH54PMx9QEwsmc5Zt+FeoAn39Q7SE # 2hHxc7Gz7iuAhIoiGN/r2j3EF3+rGSs+QtxnjupRPfDWVtTnKC3r07G1decfBmWN # lCnT2exp39mQh0YAe9tEQYncfGpXevA3eZ9drMvohGS0UvJ2R/dhgxndX7RUCyFo # bjchu0CsX7LeSn3O9TkSZ+8OpWNs5KbFHc02DVzV5huowWR0QKfAcsW6Th+xtVhN # ef7Xj3OTrCw54qVI1vCwMROpVymWJy71h6aPTnYVVSZwmCZ/oBpHIEPjQ2OAe3Vu # JyWQmDo4EbP29p7mO1vsgd4iFNmCKseSv6De4z6ic/rnH1pslPJSlRErWHRAKKtz # Q87fSqEcazjFKfPKqpZzQmiftkaznTqj1QPgv/CiPMpC3BhIfxQ0z9JMq++bPf4O # uGQq+nUoJEHtQr8FnGZJUlD0UfM2SU2LINIsVzV5K6jzRWC8I41Y99xh3pP+OcD5 # sjClTNfpmEpYPtMDiP6zj9NeS3YSUZPJjAw7W4oiqMEmCPkUEBIDfV8ju2TjY+Cm # 4T72wnSyPx4JduyrXUZ14mCjWAkBKAAOhFTuzuldyF4wEr1GnrXTdrnSDmuZDNIz # tM2xAgMBAAGjggFdMIIBWTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBS6 # FtltTYUvcyl2mi91jGogj57IbzAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qY # rhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYB # BQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20w # QQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy # dFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwz # LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZ # MBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAfVmO # wJO2b5ipRCIBfmbW2CFC4bAYLhBNE88wU86/GPvHUF3iSyn7cIoNqilp/GnBzx0H # 6T5gyNgL5Vxb122H+oQgJTQxZ822EpZvxFBMYh0MCIKoFr2pVs8Vc40BIiXOlWk/ # R3f7cnQU1/+rT4osequFzUNf7WC2qk+RZp4snuCKrOX9jLxkJodskr2dfNBwCnzv # qLx1T7pa96kQsl3p/yhUifDVinF2ZdrM8HKjI/rAJ4JErpknG6skHibBt94q6/ae # sXmZgaNWhqsKRcnfxI2g55j7+6adcq/Ex8HBanHZxhOACcS2n82HhyS7T6NJuXdm # kfFynOlLAlKnN36TU6w7HQhJD5TNOXrd/yVjmScsPT9rp/Fmw0HNT7ZAmyEhQNC3 # EyTN3B14OuSereU0cZLXJmvkOHOrpgFPvT87eK1MrfvElXvtCl8zOYdBeHo46Zzh # 3SP9HSjTx/no8Zhf+yvYfvJGnXUsHicsJttvFXseGYs2uJPU5vIXmVnKcPA3v5gA # 3yAWTyf7YGcWoWa63VXAOimGsJigK+2VQbc61RWYMbRiCQ8KvYHZE/6/pNHzV9m8 # BPqC3jLfBInwAM1dwvnQI38AC+R2AibZ8GV2QqYphwlHK+Z/GqSFD/yYlvZVVCsf # gPrA8g4r5db7qS9EFUrnEw4d2zc4GqEr9u3WfPwwggbAMIIEqKADAgECAhAMTWly # S5T6PCpKPSkHgD1aMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYD # VQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBH # NCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjIwOTIxMDAwMDAw # WhcNMzMxMTIxMjM1OTU5WjBGMQswCQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNl # cnQxJDAiBgNVBAMTG0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIyIC0gMjCCAiIwDQYJ # KoZIhvcNAQEBBQADggIPADCCAgoCggIBAM/spSY6xqnya7uNwQ2a26HoFIV0Mxom # rNAcVR4eNm28klUMYfSdCXc9FZYIL2tkpP0GgxbXkZI4HDEClvtysZc6Va8z7GGK # 6aYo25BjXL2JU+A6LYyHQq4mpOS7eHi5ehbhVsbAumRTuyoW51BIu4hpDIjG8b7g # L307scpTjUCDHufLckkoHkyAHoVW54Xt8mG8qjoHffarbuVm3eJc9S/tjdRNlYRo # 44DLannR0hCRRinrPibytIzNTLlmyLuqUDgN5YyUXRlav/V7QG5vFqianJVHhoV5 # PgxeZowaCiS+nKrSnLb3T254xCg/oxwPUAY3ugjZNaa1Htp4WB056PhMkRCWfk3h # 3cKtpX74LRsf7CtGGKMZ9jn39cFPcS6JAxGiS7uYv/pP5Hs27wZE5FX/NurlfDHn # 88JSxOYWe1p+pSVz28BqmSEtY+VZ9U0vkB8nt9KrFOU4ZodRCGv7U0M50GT6Vs/g # 9ArmFG1keLuY/ZTDcyHzL8IuINeBrNPxB9ThvdldS24xlCmL5kGkZZTAWOXlLimQ # prdhZPrZIGwYUWC6poEPCSVT8b876asHDmoHOWIZydaFfxPZjXnPYsXs4Xu5zGcT # B5rBeO3GiMiwbjJ5xwtZg43G7vUsfHuOy2SJ8bHEuOdTXl9V0n0ZKVkDTvpd6kVz # HIR+187i1Dp3AgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/ # BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEE # AjALBglghkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8w # HQYDVR0OBBYEFGKK3tBh/I8xFO2XC809KpQU31KcMFoGA1UdHwRTMFEwT6BNoEuG # SWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQw # OTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQG # CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKG # TGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJT # QTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIB # AFWqKhrzRvN4Vzcw/HXjT9aFI/H8+ZU5myXm93KKmMN31GT8Ffs2wklRLHiIY1UJ # RjkA/GnUypsp+6M/wMkAmxMdsJiJ3HjyzXyFzVOdr2LiYWajFCpFh0qYQitQ/Bu1 # nggwCfrkLdcJiXn5CeaIzn0buGqim8FTYAnoo7id160fHLjsmEHw9g6A++T/350Q # p+sAul9Kjxo6UrTqvwlJFTU2WZoPVNKyG39+XgmtdlSKdG3K0gVnK3br/5iyJpU4 # GYhEFOUKWaJr5yI+RCHSPxzAm+18SLLYkgyRTzxmlK9dAlPrnuKe5NMfhgFknADC # 6Vp0dQ094XmIvxwBl8kZI4DXNlpflhaxYwzGRkA7zl011Fk+Q5oYrsPJy8P7mxNf # arXH4PMFw1nfJ2Ir3kHJU7n/NBBn9iYymHv+XEKUgZSCnawKi8ZLFUrTmJBFYDOA # 4CPe+AOk9kVH5c64A0JH6EE2cXet/aLol3ROLtoeHYxayB6a1cLwxiKoT5u92Bya # UcQvmvZfpyeXupYuhVfAYOd4Vn9q78KVmksRAsiCnMkaBXy6cbVOepls9Oie1FqY # yJ+/jbsYXEP10Cro4mLueATbvdH7WwqocH7wl4R44wgDXUcsY6glOJcB0j862uXl # 9uab3H4szP8XTE0AotjWAQ64i+7m4HJViSwnGWH2dwGMMYIFXTCCBVkCAQEwgYYw # cjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ # d3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVk # IElEIENvZGUgU2lnbmluZyBDQQIQBNXcH0jqydhSALrNmpsqpzANBglghkgBZQME # AgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEM # BgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqG # SIb3DQEJBDEiBCD6lw6SVaTG+4BJPQlthbLcjpfAOdtTioTpSbPItsiZtDANBgkq # hkiG9w0BAQEFAASCAQCbiVbtInAYaHlZFhMRfwS5DwVuoLSdA0DdfrWoNbCSA3E9 # SM7WzX4y+3Pj28i2jnufx07r7f2gEpr3vGN+72DMPxrBOxkVtMv0zZgXAK9hNZ3D # sqxRK/FaoQtE3wDmET3BCmlWOtqrNv5qTwAEhywJptmTtKGa5Q12k4X0rxfL/Nfm # Jh86KerY6wr3bb4jYSAylr03hLfOOvy/fSXT3i6cJWf6xzyNa02ZAWROWfx7lDAa # BW0VnUppb8jz4iOSINHDifULt8qwiHS148BOtE65upbZBo/K+dMEwnqiYhvZw/qq # gnXNdbpACA08UKeHzDABg5F5y0iV35MbLMIH5XmXoYIDIDCCAxwGCSqGSIb3DQEJ # BjGCAw0wggMJAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0 # LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hB # MjU2IFRpbWVTdGFtcGluZyBDQQIQDE1pckuU+jwqSj0pB4A9WjANBglghkgBZQME # AgEFAKBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X # DTIyMTIzMDE5MTE1N1owLwYJKoZIhvcNAQkEMSIEIMCMaH+4K2FutE0gV2yHfHTF # CVS96neYAwZT3L3YdhF/MA0GCSqGSIb3DQEBAQUABIICAIEIVZLKUUide78seE5U # bvx6Rs+hGodM8Bg5NIJrWJzogbviTHQ9q2npS+bhkzvDLtKvURCZTJVQ/jelINQv # Gq/bT0LrLV2603HfiDU6ZxVlY++F+PG3ylJOwcpj8rteSsRzDEonxy9vB6+f2yFh # gUDc4o84NI6kS+eFz42MHiBfkibNvIbBzyhahqFrHYO28w0ETanNleBWlC4sE/sQ # 44e4E6Sq28WxQ8yPtmWcz1aVt9tXf8m9t4ULr6RWO5tznKIaRFPEmGAndvNE20i9 # YWad7U3NQIyAUid+OgK3bZHn9k6PfQD7aHua6dobxwsoobcchUcec9KwGXeCmkA5 # H2MteBuHoJvmMMKxn53GkxKSvnVNS2JTUMJ2B10zS00ZWRH+GeODMQpzqkUUufGM # q+q00rdOP/Gq0OuVgSBVDL56PnfOFABAVi3+71TkqgPYaFtTG50hxT88kGb43QmA # JIYbBi3x6fVZ/szbpkOaHl2F1u1FiglduWwWuKdvIYEMEWOKmGIzlbawNcpSiL7R # Pa2Uvht1DullyXE1GZaC8szMFx3VznPkTDV9M6LMc+6oKaVJW1F7ECEJyhcJNfkB # aSHbVK6rUtgDasnw++CeRqgVnmiNKlk/wJhwYwASae6n2ZgjwEnGMYd0AsF3dJkK # f1A/jBrPzedUEIq2pkBUhUJ2 # SIG # End signature block |